diff --git a/core/lib/Drupal/Core/Field/Entity/BaseFieldOverride.php b/core/lib/Drupal/Core/Field/Entity/BaseFieldOverride.php
index 9dd33973bf45cc4096df034d42d856fed7ab6233..4a7c52d727b813b33304cfed3cb4df9287d6516c 100644
--- a/core/lib/Drupal/Core/Field/Entity/BaseFieldOverride.php
+++ b/core/lib/Drupal/Core/Field/Entity/BaseFieldOverride.php
@@ -95,10 +95,6 @@ public function __construct(array $values, $entity_type = 'base_field_override')
       throw new FieldException(String::format('Attempt to create a base field bundle override of field @field_name without a bundle', array('@field_name' => $values['field_name'])));
     }
 
-    // Discard the 'field_type' entry that is added in config records to ease
-    // schema generation. See self::toArray().
-    unset($values['field_type']);
-
     parent::__construct($values, $entity_type);
   }
 
diff --git a/core/lib/Drupal/Core/Field/FieldConfigBase.php b/core/lib/Drupal/Core/Field/FieldConfigBase.php
index af5760049dafa844de896bab4ff5953c64ffc8f1..1d124801a237ef562d3d6383a7be551ee4b16d5b 100644
--- a/core/lib/Drupal/Core/Field/FieldConfigBase.php
+++ b/core/lib/Drupal/Core/Field/FieldConfigBase.php
@@ -35,6 +35,19 @@ abstract class FieldConfigBase extends ConfigEntityBase implements FieldConfigIn
    */
   public $field_name;
 
+  /**
+   * The field type.
+   *
+   * This property is denormalized from the field storage for optimization of
+   * the "entity and render cache hits" critical paths. If not present in the
+   * $values passed to create(), it is populated from the field storage in
+   * postCreate(), and saved in config records so that it is present on
+   * subsequent loads.
+   *
+   * @var string
+   */
+  public $field_type;
+
   /**
    * The name of the entity type the instance is attached to.
    *
@@ -190,7 +203,7 @@ public function getName() {
    * {@inheritdoc}
    */
   public function getType() {
-    return $this->getFieldStorageDefinition()->getType();
+    return $this->field_type;
   }
 
   /**
@@ -207,20 +220,6 @@ public function targetBundle() {
     return $this->bundle;
   }
 
-  /**
-   * {@inheritdoc}
-   */
-  public function toArray() {
-    $properties = parent::toArray();
-    // Additionally, include the field type, that is needed to be able to
-    // generate the field-type-dependant parts of the config schema and to
-    // allow for mapping settings from storage by field type.
-    // @see \Drupal\field\FieldInstanceConfigStorage::mapFromStorageRecords().
-    $properties['field_type'] = $this->getType();
-
-    return $properties;
-  }
-
   /**
    * {@inheritdoc}
    */
@@ -236,6 +235,19 @@ public function calculateDependencies() {
     return $this->dependencies;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function postCreate(EntityStorageInterface $storage) {
+    parent::postCreate($storage);
+    // If it was not present in the $values passed to create(), (e.g. for
+    // programmatic creation), populate the denormalized field_type property
+    // from the field storage, so that it gets saved in the config record.
+    if (empty($this->field_type)) {
+      $this->field_type = $this->getFieldStorageDefinition()->getType();
+    }
+  }
+
   /**
    * {@inheritdoc}
    */
diff --git a/core/modules/field/src/Entity/FieldInstanceConfig.php b/core/modules/field/src/Entity/FieldInstanceConfig.php
index 81b939669b98d6dd50e2e1fc866d526064fe1f7f..e07c4eda12631c511371a2fb5a02a2eff7d4001f 100644
--- a/core/modules/field/src/Entity/FieldInstanceConfig.php
+++ b/core/modules/field/src/Entity/FieldInstanceConfig.php
@@ -87,7 +87,9 @@ public function __construct(array $values, $entity_type = 'field_instance_config
       $field_storage = $values['field_storage'];
       $values['field_name'] = $field_storage->getName();
       $values['entity_type'] = $field_storage->getTargetEntityTypeId();
-      $this->fieldStorage = $field_storage;
+      // The internal property is fieldStorage, not field_storage.
+      unset($values['field_storage']);
+      $values['fieldStorage'] = $field_storage;
     }
     else {
       if (empty($values['field_name'])) {
@@ -102,11 +104,6 @@ public function __construct(array $values, $entity_type = 'field_instance_config
       throw new FieldException(String::format('Attempt to create a field instance @field_name without a bundle.', array('@field_name' => $values['field_name'])));
     }
 
-    // Discard the 'field_type' entry that is added in config records to ease
-    // schema generation and mapping settings from storage.
-    // @see \Drupal\Core\Field\FieldConfigBase::toArray().
-    unset($values['field_type']);
-
     parent::__construct($values, $entity_type);
   }
 
@@ -114,6 +111,8 @@ public function __construct(array $values, $entity_type = 'field_instance_config
    * {@inheritdoc}
    */
   public function postCreate(EntityStorageInterface $storage) {
+    parent::postCreate($storage);
+
     // Validate that we have a valid storage for this instance. This throws an
     // exception if the storage is invalid.
     $this->getFieldStorageDefinition();
diff --git a/core/modules/field/tests/src/FieldInstanceConfigEntityUnitTest.php b/core/modules/field/tests/src/FieldInstanceConfigEntityUnitTest.php
index 1df4023445c795e3e9e0707aecf46cb0ec39d1b1..56f28579b2aa058adaebaa08b81679abfa05953e 100644
--- a/core/modules/field/tests/src/FieldInstanceConfigEntityUnitTest.php
+++ b/core/modules/field/tests/src/FieldInstanceConfigEntityUnitTest.php
@@ -125,9 +125,13 @@ public function testCalculateDependencies() {
       ->method('getConfigDependencyName')
       ->will($this->returnValue('field.storage.test_entity_type.test_field'));
 
-    $values = array('field_name' => $this->fieldStorage->getName(), 'entity_type' => 'test_entity_type', 'bundle' => 'test_bundle');
-    $entity = new FieldInstanceConfig($values, $this->entityTypeId);
-    $dependencies = $entity->calculateDependencies();
+    $instance = new FieldInstanceConfig(array(
+      'field_name' => $this->fieldStorage->getName(),
+      'entity_type' => 'test_entity_type',
+      'bundle' => 'test_bundle',
+      'field_type' => 'test_field',
+    ), $this->entityTypeId);
+    $dependencies = $instance->calculateDependencies();
     $this->assertContains('field.storage.test_entity_type.test_field', $dependencies['entity']);
     $this->assertContains('test.test_entity_type.id', $dependencies['entity']);
   }
@@ -136,8 +140,12 @@ public function testCalculateDependencies() {
    * @covers ::toArray()
    */
   public function testToArray() {
-    $values = array('field_name' => $this->fieldStorage->getName(), 'entity_type' => 'test_entity_type', 'bundle' => 'test_bundle');
-    $instance = new FieldInstanceConfig($values, $this->entityTypeId);
+    $instance = new FieldInstanceConfig(array(
+      'field_name' => $this->fieldStorage->getName(),
+      'entity_type' => 'test_entity_type',
+      'bundle' => 'test_bundle',
+      'field_type' => 'test_field',
+    ), $this->entityTypeId);
 
     $expected = array(
       'id' => 'test_entity_type.test_bundle.field_test',
@@ -171,4 +179,26 @@ public function testToArray() {
     $export = $instance->toArray();
     $this->assertEquals($expected, $export);
   }
+
+  /**
+   * @covers ::getType
+   */
+  public function testGetType() {
+    // Ensure that FieldInstanceConfig::getType() is not delegated to
+    // FieldStorage.
+    $this->entityManager->expects($this->never())
+      ->method('getFieldStorageDefinitions');
+    $this->fieldStorage->expects($this->never())
+      ->method('getType');
+
+    $instance = new FieldInstanceConfig(array(
+      'field_name' => $this->fieldStorage->getName(),
+      'entity_type' => 'test_entity_type',
+      'bundle' => 'test_bundle',
+      'field_type' => 'test_field',
+    ), $this->entityTypeId);
+
+    $this->assertEquals('test_field', $instance->getType());
+  }
+
 }