diff --git a/core/modules/field/field.api.php b/core/modules/field/field.api.php
index 9f81f860bf47cfc57be6bdacc8407ef55e5aee12..7f5dec53013d796365b675bab2d1715d2bb86212 100644
--- a/core/modules/field/field.api.php
+++ b/core/modules/field/field.api.php
@@ -112,9 +112,6 @@ function hook_field_extra_fields_alter(&$info) {
  * appears in edit forms, while @link field_formatter formatters @endlink
  * specify how the field appears in displayed entities.
  *
- * A third kind of pluggable handler, storage backends, is defined by the
- * @link field_storage Field Storage API @endlink.
- *
  * See @link field Field API @endlink for information about the other parts of
  * the Field API.
  */
@@ -541,11 +538,10 @@ function hook_field_update_forbid($field, $prior_field) {
 /**
  * Acts when a field record is being purged.
  *
- * In field_purge_field(), after the field configuration has been removed from
- * the database, the field storage module has had a chance to run its
- * hook_field_storage_purge_field(), and the field info cache has been cleared,
- * this hook is invoked on all modules to allow them to respond to the field
- * being purged.
+ * In field_purge_field(), after the field definition has been removed from the
+ * the system, the entity storage has purged stored field data, and the field
+ * info cache has been cleared, this hook is invoked on all modules to allow
+ * them to respond to the field being purged.
  *
  * @param $field
  *   The field being purged.
@@ -559,11 +555,10 @@ function hook_field_purge_field($field) {
 /**
  * Acts when a field instance is being purged.
  *
- * In field_purge_instance(), after the field instance has been removed from the
- * database, the field storage module has had a chance to run its
- * hook_field_storage_purge_instance(), and the field info cache has been
- * cleared, this hook is invoked on all modules to allow them to respond to the
- * field instance being purged.
+ * In field_purge_instance(), after the instance definition has been removed
+ * from the the system, the entity storage has purged stored field data, and the
+ * field info cache has been cleared, this hook is invoked on all modules to
+ * allow them to respond to the field instance being purged.
  *
  * @param $instance
  *   The instance being purged.
diff --git a/core/modules/field/field.attach.inc b/core/modules/field/field.attach.inc
index 29036c75c3aad1e85876083aa549cd0e744cfa18..f12459ba19507bb9b8938b3e8695e5e136b2c97e 100644
--- a/core/modules/field/field.attach.inc
+++ b/core/modules/field/field.attach.inc
@@ -48,22 +48,7 @@
  * allows any module to act on Field Attach operations for any entity after the
  * operation is complete, and access or modify all the field, form, or display
  * data for that entity and operation. For example, field_attach_view() invokes
- * hook_field_attach_view_alter(). These all-module hooks are distinct from
- * those of the Field Types API, such as hook_field_load(), that are only
- * invoked for the module that defines a specific field type.
- *
- * field_attach_load(), field_attach_insert(), and field_attach_update() also
- * define pre-operation hooks, e.g. hook_field_attach_pre_load(). These hooks
- * run before the corresponding Field Storage API and Field Type API operations.
- * They allow modules to define additional storage locations (e.g.
- * denormalizing, mirroring) for field data on a per-field basis. They also
- * allow modules to take over field storage completely by instructing other
- * implementations of the same hook and the Field Storage API itself not to
- * operate on specified fields.
- *
- * The pre-operation hooks do not make the Field Storage API irrelevant. The
- * Field Storage API is essentially the "fallback mechanism" for any fields that
- * aren't being intercepted explicitly by pre-operation hooks.
+ * hook_field_attach_view_alter().
  *
  * @link field_language Field language API @endlink provides information about
  * the structure of field objects.
diff --git a/core/modules/field/field.module b/core/modules/field/field.module
index 1a673bce786c46e4fec1114f32af2952bf1b78ce..dabe6e7389f5528aff18f9d138e02ccf9328f148 100644
--- a/core/modules/field/field.module
+++ b/core/modules/field/field.module
@@ -69,10 +69,6 @@
  *   fields, instances, widgets, and related information defined by or with the
  *   Field API.
  *
- * - @link field_storage Field Storage API @endlink: Provides a pluggable back
- *   -end storage system for actual field data. The default implementation,
- *   field_sql_storage.module, stores field data in the local SQL database.
- *
  * - @link field_purge Field API bulk data deletion @endlink: Cleans up after
  *   bulk deletion operations such as deletion of field or field_instance.
  *
@@ -113,15 +109,11 @@
 
 /**
  * Load the most recent version of an entity's field data.
- *
- * @see field_attach_load().
  */
 const FIELD_LOAD_CURRENT = 'FIELD_LOAD_CURRENT';
 
 /**
  * Load the version of an entity's field data specified in the entity.
- *
- * @see field_attach_load().
  */
 const FIELD_LOAD_REVISION = 'FIELD_LOAD_REVISION';
 
@@ -159,10 +151,7 @@ function field_help($path, $arg) {
         '#theme' => 'item_list',
         '#items' => $items['items'],
       );
-      $output .= drupal_render($item_list) . '</dd>';
-      $output .= '<dt>' . t('Managing field data storage') . '</dt>';
-      $output .= '<dd>' . t('Developers of field modules can either use the default <a href="@sql-store">Field SQL Storage module</a> to store data for their fields, or a contributed or custom module developed using the <a href="@storage-api">field storage API</a>.', array('@storage-api' => 'http://api.drupal.org/api/group/field_storage/8', '@sql-store' => url('admin/help/field_sql_storage'))) . '</dd>';
-      $output .= '</dl>';
+      $output .= drupal_render($item_list);
       return $output;
   }
 }
diff --git a/core/modules/field/field.purge.inc b/core/modules/field/field.purge.inc
index 7333f978f005c3df853963d4f6d2ff46553b9074..e38f57fc3c6f320277a00ef1d178cdba63b7e961 100644
--- a/core/modules/field/field.purge.inc
+++ b/core/modules/field/field.purge.inc
@@ -2,7 +2,7 @@
 
 /**
  * @file
- * Field CRUD API, handling field and field instance creation and deletion.
+ * Provides support for field data purge after mass deletion.
  */
 
 use Drupal\field\Entity\Field;
@@ -17,26 +17,21 @@
  * entities as well as deleting entire fields or field instances in a single
  * operation.
  *
- * Deleting field data items for an entity with field_attach_delete() involves
- * three separate operations:
- * - Invoking the Field Type API hook_field_delete() for each field on the
- *   entity. The hook for each field type receives the entity and the specific
- *   field being deleted. A file field module might use this hook to delete
- *   uploaded files from the filesystem.
- * - Invoking the Field Storage API hook_field_storage_delete() to remove data
- *   from the primary field storage. The hook implementation receives the entity
- *   being deleted and deletes data for all of the entity's bundle's fields.
- * - Invoking the global Field Attach API hook_field_attach_delete() for all
- *   modules that implement it. Each hook implementation receives the entity
- *   being deleted and can operate on whichever subset of the entity's bundle's
- *   fields it chooses to.
+ * When a single entity is deleted, the Entity storage controller performs the
+ * following operations:
+ * - Invoking the FieldInterface delete() method for each field on the
+ *   entity. A file field type might use this method to delete uploaded files
+ *   from the filesystem.
+ * - Removing the data from storage.
+ * - Invoking the global hook_entity_delete() for all modules that implement it.
+ *   Each hook implementation receives the entity being deleted and can operate
+ *   on whichever subset of the entity's bundle's fields it chooses to.
  *
- * These hooks are invoked immediately when field_attach_delete() is called.
- * Similar operations are performed for field_attach_delete_revision().
+ * Similar operations are performed on deletion of a single entity revision.
  *
  * When a field, bundle, or field instance is deleted, it is not practical to
- * invoke these hooks immediately on every affected entity in a single page
- * request; there could be thousands or millions of them. Instead, the
+ * perform those operations immediately on every affected entity in a single
+ * page request; there could be thousands or millions of them. Instead, the
  * appropriate field data items, instances, and/or fields are marked as deleted
  * so that subsequent load or query operations will not return them. Later, a
  * separate process cleans up, or "purges", the marked-as-deleted data by going
@@ -44,34 +39,18 @@
  * field and instance records.
  *
  * Purging field data is made somewhat tricky by the fact that, while
- * field_attach_delete() has a complete entity to pass to the various deletion
- * hooks, the Field API purge process only has the field data it has previously
+ * $entity->delete() has a complete entity to pass to the various deletion
+ * steps, the Field API purge process only has the field data it has previously
  * stored. It cannot reconstruct complete original entities to pass to the
- * deletion hooks. It is even possible that the original entity to which some
- * Field API data was attached has been itself deleted before the field purge
- * operation takes place.
+ * deletion operations. It is even possible that the original entity to which
+ * some Field API data was attached has been itself deleted before the field
+ * purge operation takes place.
  *
- * Field API resolves this problem by using "pseudo-entities" during purge
- * operations. A pseudo-entity contains only the information from the original
- * entity that Field API knows about: entity type, ID, revision ID, and bundle.
- * It also contains the field data for whichever field instance is currently
- * being purged. For example, suppose that the node type 'story' used to contain
- * a field called 'subtitle' but the field was deleted. If node 37 was a story
- * with a subtitle, the pseudo-entity passed to the purge hooks would look
- * something like this:
- *
- * @code
- *   $entity = stdClass Object(
- *     [nid] => 37,
- *     [vid] => 37,
- *     [type] => 'story',
- *     [subtitle] => array(
- *       [0] => array(
- *         'value' => 'subtitle text',
- *       ),
- *     ),
- *   );
- * @endcode
+ * Field API resolves this problem by using stub entities during purge
+ * operations, containing only the information from the original entity that
+ * Field API knows about: entity type, ID, revision ID, and bundle. It also
+ * contains the field data for whichever field instance is currently being
+ * purged.
  *
  * See @link field Field API @endlink for information about the other parts of
  * the Field API.
diff --git a/core/modules/field/lib/Drupal/field/Tests/FieldAttachStorageTest.php b/core/modules/field/lib/Drupal/field/Tests/FieldAttachStorageTest.php
index 92c88f2301dec8956d213bd5389a7c87bbd12e69..103521290e3d79af5be42d8c4833060fc5174a6a 100644
--- a/core/modules/field/lib/Drupal/field/Tests/FieldAttachStorageTest.php
+++ b/core/modules/field/lib/Drupal/field/Tests/FieldAttachStorageTest.php
@@ -7,13 +7,8 @@
 
 namespace Drupal\field\Tests;
 
-use Drupal\Core\Language\Language;
-
 /**
- * Unit test class for storage-related field_attach_* functions.
- *
- * All field_attach_* test work with all field_storage plugins and
- * all hook_field_attach_pre_{load,insert,update}() hooks.
+ * Unit test class for storage-related field behavior.
  */
 class FieldAttachStorageTest extends FieldUnitTestBase {
 
diff --git a/core/modules/field/tests/modules/field_test/field_test.storage.inc b/core/modules/field/tests/modules/field_test/field_test.storage.inc
deleted file mode 100644
index 3bbbae2f3e1cdeed6eb4981c1260759fea52d467..0000000000000000000000000000000000000000
--- a/core/modules/field/tests/modules/field_test/field_test.storage.inc
+++ /dev/null
@@ -1,463 +0,0 @@
-<?php
-
-/**
- * @file
- * Defines a field storage backend.
- */
-
-use Drupal\Core\Entity\EntityInterface;
-use Drupal\field\FieldInstanceInterface;
-
-/**
- * Implements hook_field_storage_info().
- */
-function field_test_field_storage_info() {
-  return array(
-    'field_test_storage' => array(
-      'label' => t('Test storage'),
-      'description' => t('Dummy test storage backend. Stores field values in the variable table.'),
-    ),
-    'field_test_storage_failure' => array(
-      'label' => t('Test storage failure'),
-      'description' => t('Dummy test storage backend. Always fails to create fields.'),
-    ),
-  );
-}
-
-/**
- * Implements hook_field_storage_details().
- */
-function field_test_field_storage_details($field) {
-  $details = array();
-
-  // Add field columns.
-  $columns = array();
-  foreach ((array) $field['columns'] as $column_name => $attributes) {
-    $columns[$column_name] = $column_name;
-  }
-  return array(
-    'drupal_variables' => array(
-      'field_test_storage_data[FIELD_LOAD_CURRENT]' => $columns,
-      'field_test_storage_data[FIELD_LOAD_REVISION]' => $columns,
-    ),
-  );
-}
-
-/**
- * Implements hook_field_storage_details_alter().
- *
- * @see FieldAttachStorageTestCase::testFieldStorageDetailsAlter()
- */
-function field_test_field_storage_details_alter(&$details, $field) {
-
-  // For testing, storage details are changed only because of the field name.
-  if ($field['field_name'] == 'field_test_change_my_details') {
-    $columns = array();
-    foreach ((array) $field['columns'] as $column_name => $attributes) {
-      $columns[$column_name] = $column_name;
-    }
-    $details['drupal_variables'] = array(
-      FIELD_LOAD_CURRENT => array(
-        'moon' => $columns,
-      ),
-      FIELD_LOAD_REVISION => array(
-        'mars' => $columns,
-      ),
-    );
-  }
-}
-
-/**
- * Helper function: stores or retrieves data from the 'storage backend'.
- */
-function _field_test_storage_data($data = NULL) {
-  if (!isset($data)) {
-    return Drupal::state()->get('field_test.storage_data');
-  }
-  else {
-    Drupal::state()->set('field_test.storage_data', $data);
-  }
-}
-
-/**
- * Implements hook_field_storage_load().
- */
-function field_test_field_storage_load($entity_type, $entities, $age, $fields, $options) {
-  $data = _field_test_storage_data();
-
-  $load_current = $age == FIELD_LOAD_CURRENT;
-
-  foreach ($fields as $field_id => $ids) {
-    $field = field_info_field_by_id($field_id);
-    $field_name = $field['field_name'];
-    $field_data = $data[$field['uuid']];
-    $sub_table = $load_current ? 'current' : 'revisions';
-    $delta_count = array();
-    foreach ($field_data[$sub_table] as $row) {
-      if ($row->type == $entity_type && (!$row->deleted || $options['deleted'])) {
-        if (($load_current && in_array($row->entity_id, $ids)) || (!$load_current && in_array($row->revision_id, $ids))) {
-          if (in_array($row->langcode, field_available_languages($entity_type, $field))) {
-            if (!isset($delta_count[$row->entity_id][$row->langcode])) {
-              $delta_count[$row->entity_id][$row->langcode] = 0;
-            }
-            if ($field['cardinality'] == FIELD_CARDINALITY_UNLIMITED || $delta_count[$row->entity_id][$row->langcode] < $field['cardinality']) {
-              $item = array();
-              foreach ($field['columns'] as $column => $attributes) {
-                $item[$column] = $row->{$column};
-              }
-              $entities[$row->entity_id]->{$field_name}[$row->langcode][] = $item;
-              $delta_count[$row->entity_id][$row->langcode]++;
-            }
-          }
-        }
-      }
-    }
-  }
-}
-
-/**
- * Implements hook_field_storage_write().
- */
-function field_test_field_storage_write(EntityInterface $entity, $op, $fields) {
-  $data = _field_test_storage_data();
-
-  $id = $entity->id();
-  $vid = $entity->getRevisionId();
-  $bundle = $entity->bundle();
-
-  foreach ($fields as $field_id) {
-    $field = field_info_field_by_id($field_id);
-    $field_name = $field['field_name'];
-    $field_data = &$data[$field_id];
-
-    $all_langcodes = field_available_languages($entity->entityType(), $field);
-    $field_langcodes = array_intersect($all_langcodes, array_keys((array) $entity->$field_name));
-
-    // Delete and insert, rather than update, in case a value was added.
-    if ($op == FIELD_STORAGE_UPDATE) {
-      // Delete languages present in the incoming $entity->$field_name.
-      // Delete all languages if $entity->$field_name is empty.
-      $langcodes = !empty($entity->$field_name) ? $field_langcodes : $all_langcodes;
-      if ($langcodes) {
-        foreach ($field_data['current'] as $key => $row) {
-          if ($row->type == $entity->entityType() && $row->entity_id == $id && in_array($row->langcode, $langcodes)) {
-            unset($field_data['current'][$key]);
-          }
-        }
-        if (isset($vid)) {
-          foreach ($field_data['revisions'] as $key => $row) {
-            if ($row->type == $entity->entityType() && $row->revision_id == $vid) {
-              unset($field_data['revisions'][$key]);
-            }
-          }
-        }
-      }
-    }
-
-    foreach ($field_langcodes as $langcode) {
-      $items = (array) $entity->{$field_name}[$langcode];
-      $delta_count = 0;
-      foreach ($items as $delta => $item) {
-        $row = (object) array(
-          'field_id' => $field_id,
-          'type' => $entity->entityType(),
-          'entity_id' => $id,
-          'revision_id' => $vid,
-          'bundle' => $bundle,
-          'delta' => $delta,
-          'deleted' => FALSE,
-          'langcode' => $langcode,
-        );
-        foreach ($field['columns'] as $column => $attributes) {
-          $row->{$column} = isset($item[$column]) ? $item[$column] : NULL;
-        }
-
-        $field_data['current'][] = $row;
-        if (isset($vid)) {
-          $field_data['revisions'][] = $row;
-        }
-
-        if ($field['cardinality'] != FIELD_CARDINALITY_UNLIMITED && ++$delta_count == $field['cardinality']) {
-          break;
-        }
-      }
-    }
-  }
-
-  _field_test_storage_data($data);
-}
-
-/**
- * Implements hook_field_storage_delete().
- */
-function field_test_field_storage_delete(EntityInterface $entity, $fields) {
-  // Note: reusing field_test_storage_purge(), like field_sql_storage.module
-  // does, is highly inefficient in our case...
-  foreach (field_info_instances($entity->entityType(), $entity->bundle()) as $instance) {
-    if (isset($fields[$instance['field_id']])) {
-      $field = $instance->getField();
-      field_test_field_storage_purge($entity, $field, $instance);
-    }
-  }
-}
-
-/**
- * Implements hook_field_storage_purge().
- */
-function field_test_field_storage_purge(EntityInterface $entity, $field, $instance) {
-  $data = _field_test_storage_data();
-
-  $field_data = &$data[$field['uuid']];
-  foreach (array('current', 'revisions') as $sub_table) {
-    foreach ($field_data[$sub_table] as $key => $row) {
-      if ($row->type == $entity->entityType() && $row->entity_id == $entity->id()) {
-        unset($field_data[$sub_table][$key]);
-      }
-    }
-  }
-
-  _field_test_storage_data($data);
-}
-
-/**
- * Implements hook_field_storage_delete_revision().
- */
-function field_test_field_storage_delete_revision(EntityInterface $entity, $fields) {
-  $data = _field_test_storage_data();
-
-  foreach ($fields as $field_id) {
-    $field_data = &$data[$field_id];
-    foreach (array('current', 'revisions') as $sub_table) {
-      foreach ($field_data[$sub_table] as $key => $row) {
-        if ($row->type == $entity->entityType() && $row->entity_id == $entity->id() && $row->revision_id == $entity->getRevisionId()) {
-          unset($field_data[$sub_table][$key]);
-        }
-      }
-    }
-  }
-
-  _field_test_storage_data($data);
-}
-
-/**
- * Implements hook_field_storage_query().
- */
-function field_test_field_storage_query($field_id, $conditions, $count, &$cursor = NULL, $age) {
-  $data = _field_test_storage_data();
-
-  $load_current = $age == FIELD_LOAD_CURRENT;
-
-  $field = field_info_field_by_id($field_id);
-  $field_columns = array_keys($field['columns']);
-
-  $field_data = $data[$field['uuid']];
-  $sub_table = $load_current ? 'current' : 'revisions';
-  // We need to sort records by entity type and entity id.
-  usort($field_data[$sub_table], '_field_test_field_storage_query_sort_helper');
-
-    // Initialize results array.
-  $return = array();
-  $entity_count = 0;
-  $rows_count = 0;
-  $rows_total = count($field_data[$sub_table]);
-  $skip = $cursor;
-  $skipped = 0;
-
-  foreach ($field_data[$sub_table] as $row) {
-    if ($count != FIELD_QUERY_NO_LIMIT && $entity_count >= $count) {
-      break;
-    }
-
-    if ($row->field_id == $field['uuid']) {
-      $match = TRUE;
-      $condition_deleted = FALSE;
-      // Add conditions.
-      foreach ($conditions as $condition) {
-        @list($column, $value, $operator) = $condition;
-        if (empty($operator)) {
-          $operator = is_array($value) ? 'IN' : '=';
-        }
-        switch ($operator) {
-          case '=':
-            $match = $match && $row->{$column} == $value;
-            break;
-          case '<>':
-          case '<':
-          case '<=':
-          case '>':
-          case '>=':
-            eval('$match = $match && ' . $row->{$column} . ' ' . $operator . ' '. $value);
-            break;
-          case 'IN':
-            $match = $match && in_array($row->{$column}, $value);
-            break;
-          case 'NOT IN':
-            $match = $match && !in_array($row->{$column}, $value);
-            break;
-          case 'BETWEEN':
-            $match = $match && $row->{$column} >= $value[0] && $row->{$column} <= $value[1];
-            break;
-          case 'STARTS_WITH':
-          case 'ENDS_WITH':
-          case 'CONTAINS':
-            // Not supported.
-            $match = FALSE;
-            break;
-        }
-        // Track condition on 'deleted'.
-        if ($column == 'deleted') {
-          $condition_deleted = TRUE;
-        }
-      }
-
-      // Exclude deleted data unless we have a condition on it.
-      if (!$condition_deleted && $row->deleted) {
-        $match = FALSE;
-      }
-
-      if ($match) {
-        if (!isset($skip) || $skipped >= $skip) {
-          $cursor++;
-          // If querying all revisions and the entity type has revisions, we need
-          // to key the results by revision_ids.
-          $entity_type = entity_get_info($row->type);
-          $id = ($load_current || empty($entity_type['entity_keys']['revision'])) ? $row->entity_id : $row->revision_id;
-
-          if (!isset($return[$row->type][$id])) {
-            $return[$row->type][$id] = (object) array('entity_id' => $row->entity_id, 'revision_id' => $row->revision_id, 'bundle' => $row->bundle);
-            $entity_count++;
-          }
-        }
-        else {
-          $skipped++;
-        }
-      }
-    }
-    $rows_count++;
-
-    // The query is complete if we walked the whole array.
-    if ($count != FIELD_QUERY_NO_LIMIT && $rows_count >= $rows_total) {
-      $cursor = FIELD_QUERY_COMPLETE;
-    }
-  }
-
-  return $return;
-}
-
-/**
- * Sort helper for field_test_field_storage_query().
- *
- * Sorts by entity type and entity id.
- */
-function _field_test_field_storage_query_sort_helper($a, $b) {
-  if ($a->type == $b->type) {
-    if ($a->entity_id == $b->entity_id) {
-      return 0;
-    }
-    else {
-      return $a->entity_id < $b->entity_id ? -1 : 1;
-    }
-  }
-  else {
-    return $a->type < $b->type ? -1 : 1;
-  }
-}
-
-/**
- * Implements hook_field_storage_create_field().
- */
-function field_test_field_storage_create_field($field) {
-  if ($field['storage']['type'] == 'field_test_storage_failure') {
-    throw new Exception('field_test_storage_failure engine always fails to create fields');
-  }
-
-  $data = _field_test_storage_data();
-
-  $data[$field['uuid']] = array(
-    'current' => array(),
-    'revisions' => array(),
-  );
-
-  _field_test_storage_data($data);
-}
-
-/**
- * Implements hook_field_storage_delete_field().
- */
-function field_test_field_storage_delete_field($field) {
-  $data = _field_test_storage_data();
-
-  $field_data = &$data[$field['uuid']];
-  foreach (array('current', 'revisions') as $sub_table) {
-    foreach ($field_data[$sub_table] as &$row) {
-      $row->deleted = TRUE;
-    }
-  }
-
-  _field_test_storage_data($data);
-}
-
-/**
- * Implements hook_field_storage_delete_instance().
- */
-function field_test_field_storage_delete_instance($instance) {
-  $data = _field_test_storage_data();
-
-  $field = $instance->getField();
-  $field_data = &$data[$field['uuid']];
-  foreach (array('current', 'revisions') as $sub_table) {
-    foreach ($field_data[$sub_table] as &$row) {
-      if ($row->bundle == $instance['bundle']) {
-        $row->deleted = TRUE;
-      }
-    }
-  }
-
-  _field_test_storage_data($data);
-}
-
-/**
- * Implements hook_entity_bundle_rename().
- */
-function field_test_entity_bundle_rename($entity_type, $bundle_old, $bundle_new) {
-  $data = _field_test_storage_data();
-
-  // We need to account for deleted or inactive fields and instances.
-  $instances = field_read_instances(array('bundle' => $bundle_new), array('include_deleted' => TRUE, 'include_inactive' => TRUE));
-  foreach ($instances as $instance) {
-    $field = $instance->getField();
-    if ($field && $field['storage']['type'] == 'field_test_storage') {
-      $field_data = &$data[$field['uuid']];
-      foreach (array('current', 'revisions') as $sub_table) {
-        foreach ($field_data[$sub_table] as &$row) {
-          if ($row->bundle == $bundle_old) {
-            $row->bundle = $bundle_new;
-          }
-        }
-      }
-    }
-  }
-
-  _field_test_storage_data($data);
-}
-
-/**
- * Implements hook_ENTITY_TYPE_delete() for 'field_instance'.
- */
-function field_test_field_instance_delete(FieldInstanceInterface $field_instance) {
-  $data = _field_test_storage_data();
-
-  $field = $field_instance->getField();
-  if ($field->storage['type'] == 'field_test_storage') {
-    $field_data = &$data[$field->uuid];
-    foreach (array('current', 'revisions') as $sub_table) {
-      foreach ($field_data[$sub_table] as &$row) {
-        if ($row->bundle == $field_instance->bundle) {
-          $row->deleted = TRUE;
-        }
-      }
-    }
-  }
-
-  _field_test_storage_data($data);
-}
diff --git a/core/modules/node/node.api.php b/core/modules/node/node.api.php
index cc7205fae4cd85690aaec09797903c3de79c8e39..275e232e55ecc670aabf814e40f7935575cbfdf3 100644
--- a/core/modules/node/node.api.php
+++ b/core/modules/node/node.api.php
@@ -492,11 +492,10 @@ function hook_node_create(\Drupal\Core\Entity\EntityInterface $node) {
  *
  * This hook is invoked during node loading, which is handled by entity_load(),
  * via classes Drupal\node\NodeStorageController and
- * Drupal\Core\Entity\DatabaseStorageController. After the node information is
- * read from the database or the entity cache, then field_attach_load_revision()
- * or field_attach_load() is called, then hook_entity_load() is invoked on all
- * implementing modules, and finally hook_node_load() is invoked on all
- * implementing modules.
+ * Drupal\Core\Entity\DatabaseStorageController. After the node information and
+ * field values are read from the database or the entity cache,
+ * hook_entity_load() is invoked on all implementing modules, and finally
+ * hook_node_load() is invoked on all implementing modules.
  *
  * @param $nodes
  *   An array of the nodes being loaded, keyed by nid.