diff --git a/core/modules/field/lib/Drupal/field/Plugin/Core/Entity/Field.php b/core/modules/field/lib/Drupal/field/Plugin/Core/Entity/Field.php
index fe6886a..9a4c413 100644
--- a/core/modules/field/lib/Drupal/field/Plugin/Core/Entity/Field.php
+++ b/core/modules/field/lib/Drupal/field/Plugin/Core/Entity/Field.php
@@ -207,6 +207,20 @@ class Field extends ConfigEntityBase implements \ArrayAccess {
   protected $storageDetails;
 
   /**
+   * The hook that is fired when saving or updating a field.
+   *
+   * @var string
+   */
+  protected $hook;
+
+  /**
+   * The arguments for firing a hook after saving or updating a field.
+   *
+   * @var array
+   */
+  protected $hook_args;
+
+  /**
    * {@inheritdoc}
    */
   public function __construct(array $values, $entity_type = 'field_entity') {
@@ -273,121 +287,134 @@ public function getExportProperties() {
    * {@inheritdoc}
    */
   public function save() {
-    $module_handler = \Drupal::moduleHandler();
-    $storage_controller = \Drupal::service('plugin.manager.entity')->getStorageController($this->entityType);
+    $this->module_handler = \Drupal::moduleHandler();
+    $this->storage_controller = \Drupal::service('plugin.manager.entity')->getStorageController($this->entityType);
 
     // Clear the derived data about the field.
     unset($this->schema, $this->storageDetails);
 
     if ($this->isNew()) {
-      // Field name cannot be longer than Field::ID_MAX_LENGTH characters. We
-      // use drupal_strlen() because the DB layer assumes that column widths
-      // are given in characters rather than bytes.
-      if (drupal_strlen($this->id) > static::ID_MAX_LENGTH) {
-        throw new FieldException(format_string(
-          'Attempt to create a field with an ID longer than @max characters: %id', array(
-            '@max' => static::ID_MAX_LENGTH,
-            '%id' => $this->id,
-          )
-        ));
-      }
+      $this->prepareNew();
+    }
+    else {
+      $this->prepareUpdate();
+    }
 
-      // Ensure the field name is unique (we do not care about deleted fields).
-      if ($prior_field = current($storage_controller->load(array($this->id)))) {
-        $message = $prior_field->active ?
-          'Attempt to create field name %id which already exists and is active.' :
-          'Attempt to create field name %id which already exists, although it is inactive.';
-        throw new FieldException(format_string($message, array('%id' => $this->id)));
-      }
+    // Save the configuration.
+    $result = parent::save();
+    field_cache_clear();
 
-      // Disallow reserved field names. This can't prevent all field name
-      // collisions with existing entity properties, but some is better than
-      // none.
-      foreach (\Drupal::service('plugin.manager.entity')->getDefinitions() as $type => $info) {
-        if (in_array($this->id, $info['entity_keys'])) {
-          throw new FieldException(format_string('Attempt to create field %id which is reserved by entity type %type.', array('%id' => $this->id, '%type' => $type)));
-        }
-      }
+    // Invoke external hooks after the cache is cleared for API consistency.
+    // This invokes either hook_field_create_field() or
+    // hook_field_update_field() depending on whether the field is new.
+    $this->module_handler->invokeAll($this->hook, $this->hook_args);
 
-      // Check that the field type is known.
-      $field_type = field_info_field_types($this->type);
-      if (!$field_type) {
-        throw new FieldException(format_string('Attempt to create a field of unknown type %type.', array('%type' => $this->type)));
-      }
-      $this->module = $field_type['module'];
-      $this->active = 1;
-
-      // Make sure all settings are present, so that a complete field
-      // definition is passed to the various hooks and written to config.
-      $this->settings += $field_type['settings'];
-
-      // Provide default storage.
-      $this->storage += array(
-        'type' => variable_get('field_storage_default', 'field_sql_storage'),
-        'settings' => array(),
-      );
-      // Check that the storage type is known.
-      $storage_type = field_info_storage_types($this->storage['type']);
-      if (!$storage_type) {
-        throw new FieldException(format_string('Attempt to create a field with unknown storage type %type.', array('%type' => $this->storage['type'])));
-      }
-      $this->storage['module'] = $storage_type['module'];
-      $this->storage['active'] = 1;
-      // Provide default storage settings.
-      $this->storage['settings'] += $storage_type['settings'];
+    return $result;
+  }
 
-      // Invoke the storage backend's hook_field_storage_create_field().
-      $module_handler->invoke($this->storage['module'], 'field_storage_create_field', array($this));
+  /**
+   * Prepares a new field definition for saving.
+   */
+  protected function prepareNew() {
+    // Field name cannot be longer than Field::ID_MAX_LENGTH characters. We
+    // use drupal_strlen() because the DB layer assumes that column widths
+    // are given in characters rather than bytes.
+    if (drupal_strlen($this->id) > static::ID_MAX_LENGTH) {
+      throw new FieldException(format_string(
+        'Attempt to create a field with an ID longer than @max characters: %id', array(
+          '@max' => static::ID_MAX_LENGTH,
+          '%id' => $this->id,
+        )
+      ));
+    }
 
-      $hook = 'field_create_field';
-      $hook_args = array($this);
+    // Ensure the field name is unique (we do not care about deleted fields).
+    if ($prior_field = current($this->storage_controller->load(array($this->id)))) {
+      $message = $prior_field->active ?
+        'Attempt to create field name %id which already exists and is active.' :
+        'Attempt to create field name %id which already exists, although it is inactive.';
+      throw new FieldException(format_string($message, array('%id' => $this->id)));
     }
-    // Otherwise, the field is being updated.
-    else {
-      $original = $storage_controller->loadUnchanged($this->id());
 
-      // Some updates are always disallowed.
-      if ($this->type != $original->type) {
-        throw new FieldException("Cannot change an existing field's type.");
-      }
-      if ($this->entity_types != $original->entity_types) {
-        throw new FieldException("Cannot change an existing field's entity_types property.");
-      }
-      if ($this->storage['type'] != $original->storage['type']) {
-        throw new FieldException("Cannot change an existing field's storage type.");
+    // Disallow reserved field names. This can't prevent all field name
+    // collisions with existing entity properties, but some is better than
+    // none.
+    foreach (\Drupal::service('plugin.manager.entity')->getDefinitions() as $type => $info) {
+      if (in_array($this->id, $info['entity_keys'])) {
+        throw new FieldException(format_string('Attempt to create field %id which is reserved by entity type %type.', array('%id' => $this->id, '%type' => $type)));
       }
+    }
 
-      // Make sure all settings are present, so that a complete field
-      // definition is saved. This allows calling code to perform partial
-      // updates on a field object.
-      $this->settings += $original->settings;
+    // Check that the field type is known.
+    $field_type = field_info_field_types($this->type);
+    if (!$field_type) {
+      throw new FieldException(format_string('Attempt to create a field of unknown type %type.', array('%type' => $this->type)));
+    }
+    $this->module = $field_type['module'];
+    $this->active = 1;
 
-      $has_data = field_has_data($this);
+    // Make sure all settings are present, so that a complete field
+    // definition is passed to the various hooks and written to config.
+    $this->settings += $field_type['settings'];
 
-      // See if any module forbids the update by throwing an exception. This
-      // invokes hook_field_update_forbid().
-      $module_handler->invokeAll('field_update_forbid', array($this, $original, $has_data));
+    // Provide default storage.
+    $this->storage += array(
+      'type' => variable_get('field_storage_default', 'field_sql_storage'),
+      'settings' => array(),
+    );
+    // Check that the storage type is known.
+    $storage_type = field_info_storage_types($this->storage['type']);
+    if (!$storage_type) {
+      throw new FieldException(format_string('Attempt to create a field with unknown storage type %type.', array('%type' => $this->storage['type'])));
+    }
+    $this->storage['module'] = $storage_type['module'];
+    $this->storage['active'] = 1;
+    // Provide default storage settings.
+    $this->storage['settings'] += $storage_type['settings'];
 
-      // Tell the storage engine to update the field by invoking the
-      // hook_field_storage_update_field(). The storage engine can reject the
-      // definition update as invalid by raising an exception, which stops
-      // execution before the definition is written to config.
-      $module_handler->invoke($this->storage['module'], 'field_storage_update_field', array($this, $original, $has_data));
+    // Invoke the storage backend's hook_field_storage_create_field().
+    $this->module_handler->invoke($this->storage['module'], 'field_storage_create_field', array($this));
 
-      $hook = 'field_update_field';
-      $hook_args = array($this, $original, $has_data);
+    $this->hook = 'field_create_field';
+    $this->hook_args = array($this);
+  }
+
+  /**
+   * Prepares a field definition for updating.
+   */
+  protected function prepareUpdate() {
+    $original = $this->storage_controller->loadUnchanged($this->id());
+
+    // Some updates are always disallowed.
+    if ($this->type != $original->type) {
+      throw new FieldException("Cannot change an existing field's type.");
+    }
+    if ($this->entity_types != $original->entity_types) {
+      throw new FieldException("Cannot change an existing field's entity_types property.");
+    }
+    if ($this->storage['type'] != $original->storage['type']) {
+      throw new FieldException("Cannot change an existing field's storage type.");
     }
 
-    // Save the configuration.
-    $result = parent::save();
-    field_cache_clear();
+    // Make sure all settings are present, so that a complete field
+    // definition is saved. This allows calling code to perform partial
+    // updates on a field object.
+    $this->settings += $original->settings;
 
-    // Invoke external hooks after the cache is cleared for API consistency.
-    // This invokes either hook_field_create_field() or
-    // hook_field_update_field() depending on whether the field is new.
-    $module_handler->invokeAll($hook, $hook_args);
+    $has_data = field_has_data($this);
 
-    return $result;
+    // See if any module forbids the update by throwing an exception. This
+    // invokes hook_field_update_forbid().
+    $this->module_handler->invokeAll('field_update_forbid', array($this, $original, $has_data));
+
+    // Tell the storage engine to update the field by invoking the
+    // hook_field_storage_update_field(). The storage engine can reject the
+    // definition update as invalid by raising an exception, which stops
+    // execution before the definition is written to config.
+    $this->module_handler->invoke($this->storage['module'], 'field_storage_update_field', array($this, $original, $has_data));
+
+    $this->hook = 'field_update_field';
+    $this->hook_args = array($this, $original, $has_data);
   }
 
   /**
diff --git a/core/modules/field/lib/Drupal/field/Plugin/Core/Entity/FieldInstance.php b/core/modules/field/lib/Drupal/field/Plugin/Core/Entity/FieldInstance.php
index 9db2f3d..9727857 100644
--- a/core/modules/field/lib/Drupal/field/Plugin/Core/Entity/FieldInstance.php
+++ b/core/modules/field/lib/Drupal/field/Plugin/Core/Entity/FieldInstance.php
@@ -225,6 +225,20 @@ class FieldInstance extends ConfigEntityBase implements \ArrayAccess {
   protected $bundle_rename_allowed = FALSE;
 
   /**
+   * The hook that is fired when saving or updating a field instance.
+   *
+   * @var string
+   */
+  protected $hook;
+
+  /**
+   * The arguments for firing a hook after saving or updating a field instance.
+   *
+   * @var array
+   */
+  protected $hook_args;
+
+  /**
    * {@inheritdoc}
    */
   public function __construct(array $values, $entity_type = 'field_instance') {
@@ -319,55 +333,18 @@ public function save() {
     $module_handler = \Drupal::moduleHandler();
     $entity_manager = \Drupal::service('plugin.manager.entity');
     $field_controller = $entity_manager->getStorageController('field_entity');
-    $instance_controller = $entity_manager->getStorageController($this->entityType);
+    $this->instance_controller = $entity_manager->getStorageController($this->entityType);
 
-    $field = current($field_controller->load(array($this->field_name)));
+    $this->field = current($field_controller->load(array($this->field_name)));
 
     if ($this->isNew()) {
-      if (empty($field)) {
-        throw new FieldException(format_string("Attempt to save an instance of a field @field_id that doesn't exist or is currently inactive.", array('@field_name' => $this->field_name)));
-      }
-      // Check that the field can be attached to this entity type.
-      if (!empty($field->entity_types) && !in_array($this->entity_type, $field->entity_types)) {
-        throw new FieldException(format_string('Attempt to create an instance of field @field_name on forbidden entity type @entity_type.', array('@field_name' => $this->field_name, '@entity_type' => $this->entity_type)));
-      }
-
-      // Assign the ID.
-      $this->id = $this->id();
-
-      // Ensure the field instance is unique within the bundle.
-      if ($prior_instance = current($instance_controller->load(array($this->id)))) {
-        throw new FieldException(format_string('Attempt to create an instance of field @field_name on bundle @bundle that already has an instance of that field.', array('@field_name' => $this->field_name, '@bundle' => $this->bundle)));
-      }
-
-      // Set the field UUID.
-      $this->field_uuid = $field->uuid;
-
-      $hook = 'field_create_instance';
-      $hook_args = array($this);
+      $this->prepareNew();
     }
-    // Otherwise, the field instance is being updated.
     else {
-      $original = \Drupal::service('plugin.manager.entity')
-        ->getStorageController($this->entityType)
-        ->loadUnchanged($this->getOriginalID());
-
-      // Some updates are always disallowed.
-      if ($this->entity_type != $original->entity_type) {
-        throw new FieldException("Cannot change an existing instance's entity_type.");
-      }
-      if ($this->bundle != $original->bundle && empty($this->bundle_rename_allowed)) {
-        throw new FieldException("Cannot change an existing instance's bundle.");
-      }
-      if ($this->field_name != $original->field_name || $this->field_uuid != $original->field_uuid) {
-        throw new FieldException("Cannot change an existing instance's field.");
-      }
-
-      $hook = 'field_update_instance';
-      $hook_args = array($this, $original);
+      $this->prepareUpdate();
     }
 
-    $field_type_info = field_info_field_types($field->type);
+    $field_type_info = field_info_field_types($this->field->type);
 
     // Set the default instance settings.
     $this->settings += $field_type_info['instance_settings'];
@@ -395,12 +372,62 @@ public function save() {
     // Invoke external hooks after the cache is cleared for API consistency.
     // This invokes hook_field_create_instance() or hook_field_update_instance()
     // depending on whether the field is new.
-    $module_handler->invokeAll($hook, $hook_args);
+    $module_handler->invokeAll($this->hook, $this->hook_args);
 
     return $result;
   }
 
   /**
+   * Prepares a field instance definition for saving.
+   */
+  protected function prepareNew() {
+    if (empty($this->field)) {
+      throw new FieldException(format_string("Attempt to save an instance of a field @field_id that doesn't exist or is currently inactive.", array('@field_name' => $this->field_name)));
+    }
+    // Check that the field can be attached to this entity type.
+    if (!empty($field->entity_types) && !in_array($this->entity_type, $this->field->entity_types)) {
+      throw new FieldException(format_string('Attempt to create an instance of field @field_name on forbidden entity type @entity_type.', array('@field_name' => $this->field_name, '@entity_type' => $this->entity_type)));
+    }
+
+    // Assign the ID.
+    $this->id = $this->id();
+
+    // Ensure the field instance is unique within the bundle.
+    if ($prior_instance = current($this->instance_controller->load(array($this->id)))) {
+      throw new FieldException(format_string('Attempt to create an instance of field @field_name on bundle @bundle that already has an instance of that field.', array('@field_name' => $this->field_name, '@bundle' => $this->bundle)));
+    }
+
+    // Set the field UUID.
+    $this->field_uuid = $this->field->uuid;
+
+    $this->hook = 'field_create_instance';
+    $this->hook_args = array($this);
+  }
+
+  /**
+   * Prepares for a field instance definition for updating.
+   */
+  protected function prepareUpdate() {
+    $original = \Drupal::service('plugin.manager.entity')
+      ->getStorageController($this->entityType)
+      ->loadUnchanged($this->getOriginalID());
+
+    // Some updates are always disallowed.
+    if ($this->entity_type != $original->entity_type) {
+      throw new FieldException("Cannot change an existing instance's entity_type.");
+    }
+    if ($this->bundle != $original->bundle && empty($this->bundle_rename_allowed)) {
+      throw new FieldException("Cannot change an existing instance's bundle.");
+    }
+    if ($this->field_name != $original->field_name || $this->field_uuid != $original->field_uuid) {
+      throw new FieldException("Cannot change an existing instance's field.");
+    }
+
+    $this->hook = 'field_update_instance';
+    $this->hook_args = array($this, $original);
+  }
+
+  /**
    * Overrides \Drupal\Core\Entity\Entity::delete().
    *
    * @param bool $field_cleanup
