diff --git a/core/includes/entity.inc b/core/includes/entity.inc
index fe30114..c2227a9 100644
--- a/core/includes/entity.inc
+++ b/core/includes/entity.inc
@@ -102,6 +102,8 @@ function entity_get_bundles($entity_type = NULL) {
  */
 function entity_invoke_bundle_hook($hook, $entity_type, $bundle, $bundle_new = NULL) {
   entity_info_cache_clear();
+  $method = 'handleBundle' . ucfirst($hook);
+  Drupal::entityManager()->getStorageController($entity_type)->$method($bundle, $bundle_new);
   module_invoke_all('entity_bundle_' . $hook, $entity_type, $bundle, $bundle_new);
 }
 
diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigEntityInterface.php b/core/lib/Drupal/Core/Config/Entity/ConfigEntityInterface.php
index 14d3f18..0d9bd71 100644
--- a/core/lib/Drupal/Core/Config/Entity/ConfigEntityInterface.php
+++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityInterface.php
@@ -75,4 +75,14 @@ public function setStatus($status);
    */
   public function status();
 
+  /**
+   * Retrieves the exportable properties of the entity.
+   *
+   * These are the values that get saved into config.
+   *
+   * @return array
+   *   An array of exportable properties and their values.
+   */
+  public function getExportProperties();
+
 }
diff --git a/core/lib/Drupal/Core/Database/Connection.php b/core/lib/Drupal/Core/Database/Connection.php
index ce7e04f..c9069b1 100644
--- a/core/lib/Drupal/Core/Database/Connection.php
+++ b/core/lib/Drupal/Core/Database/Connection.php
@@ -759,7 +759,7 @@ public function truncate($table, array $options = array()) {
    *
    * This method will lazy-load the appropriate schema library file.
    *
-   * @return Drupal\Core\Database\Schema
+   * @return \Drupal\Core\Database\Schema
    *   The database Schema object for this connection.
    */
   public function schema() {
diff --git a/core/lib/Drupal/Core/Entity/DatabaseStorageController.php b/core/lib/Drupal/Core/Entity/DatabaseStorageController.php
index e2dc1b4..2f55f05 100644
--- a/core/lib/Drupal/Core/Entity/DatabaseStorageController.php
+++ b/core/lib/Drupal/Core/Entity/DatabaseStorageController.php
@@ -7,13 +7,15 @@
 
 namespace Drupal\Core\Entity;
 
-use Drupal\Core\Language\Language;
-use PDO;
-use Drupal\Core\Cache\CacheBackendInterface;
+use Drupal\field\FieldInfo;
+use Drupal\field\FieldUpdateForbiddenException;
+use Drupal\field\FieldInterface;
+use Drupal\field\FieldInstanceInterface;
 use Drupal\Core\Entity\Query\QueryInterface;
 use Drupal\Component\Uuid\Uuid;
 use Drupal\Component\Utility\NestedArray;
 use Drupal\Core\Database\Connection;
+use Drupal\field\Plugin\Core\Entity\Field;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -24,7 +26,7 @@
  * This class can be used as-is by most simple entity types. Entity types
  * requiring special handling can extend the class.
  */
-class DatabaseStorageController extends EntityStorageControllerBase {
+class DatabaseStorageController extends FieldableEntityStorageControllerBase {
 
   /**
    * Name of entity's revision database table field, if it supports revisions.
@@ -59,13 +61,21 @@ class DatabaseStorageController extends EntityStorageControllerBase {
   protected $database;
 
   /**
+   * The field info object.
+   *
+   * @var \Drupal\field\FieldInfo
+   */
+  protected $fieldInfo;
+
+  /**
    * {@inheritdoc}
    */
   public static function createInstance(ContainerInterface $container, $entity_type, array $entity_info) {
     return new static(
       $entity_type,
       $entity_info,
-      $container->get('database')
+      $container->get('database'),
+      $container->get('field.info')
     );
   }
 
@@ -78,11 +88,14 @@ public static function createInstance(ContainerInterface $container, $entity_typ
    *   An array of entity info for the entity type.
    * @param \Drupal\Core\Database\Connection $database
    *   The database connection to be used.
+   * @param \Drupal\field\FieldInfo $field_info
+   *   The field info service.
    */
-  public function __construct($entity_type, array $entity_info, Connection $database) {
+  public function __construct($entity_type, array $entity_info, Connection $database, FieldInfo $field_info) {
     parent::__construct($entity_type, $entity_info);
 
     $this->database = $database;
+    $this->fieldInfo = $field_info;
 
     // Check if the entity type supports IDs.
     if (isset($this->entityInfo['entity_keys']['id'])) {
@@ -143,7 +156,7 @@ public function loadMultiple(array $ids = NULL) {
         // We provide the necessary arguments for PDO to create objects of the
         // specified entity class.
         // @see Drupal\Core\Entity\EntityInterface::__construct()
-        $query_result->setFetchMode(PDO::FETCH_CLASS, $this->entityInfo['class'], array(array(), $this->entityType));
+        $query_result->setFetchMode(\PDO::FETCH_CLASS, $this->entityInfo['class'], array(array(), $this->entityType));
       }
       $queried_entities = $query_result->fetchAllAssoc($this->idKey);
     }
@@ -196,7 +209,7 @@ public function loadRevision($revision_id) {
       // We provide the necessary arguments for PDO to create objects of the
       // specified entity class.
       // @see Drupal\Core\Entity\EntityInterface::__construct()
-      $query_result->setFetchMode(PDO::FETCH_CLASS, $this->entityInfo['class'], array(array(), $this->entityType));
+      $query_result->setFetchMode(\PDO::FETCH_CLASS, $this->entityInfo['class'], array(array(), $this->entityType));
     }
     $queried_entities = $query_result->fetchAllAssoc($this->idKey);
 
@@ -335,14 +348,9 @@ protected function buildQuery($ids, $revision_id = FALSE) {
    *   (optional) TRUE if the revision should be loaded, defaults to FALSE.
    */
   protected function attachLoad(&$queried_entities, $load_revision = FALSE) {
-    // Attach fields.
+    // Attach field values.
     if ($this->entityInfo['fieldable']) {
-      if ($load_revision) {
-        field_attach_load_revision($this->entityType, $queried_entities);
-      }
-      else {
-        field_attach_load($this->entityType, $queried_entities);
-      }
+      $this->fieldLoad($queried_entities, $load_revision ? FIELD_LOAD_REVISION : FIELD_LOAD_CURRENT);
     }
 
     // Call hook_entity_load().
@@ -490,7 +498,7 @@ public function save(EntityInterface $entity) {
   /**
    * Saves an entity revision.
    *
-   * @param Drupal\Core\Entity\EntityInterface $entity
+   * @param \Drupal\Core\Entity\EntityInterface $entity
    *   The entity object.
    */
   protected function saveRevision(EntityInterface $entity) {
@@ -528,31 +536,6 @@ protected function saveRevision(EntityInterface $entity) {
   }
 
   /**
-   * Invokes a hook on behalf of the entity.
-   *
-   * @param $hook
-   *   One of 'presave', 'insert', 'update', 'predelete', 'delete', or
-   *  'revision_delete'.
-   * @param $entity
-   *   The entity object.
-   */
-  protected function invokeHook($hook, EntityInterface $entity) {
-    $function = 'field_attach_' . $hook;
-    // @todo: field_attach_delete_revision() is named the wrong way round,
-    // consider renaming it.
-    if ($function == 'field_attach_revision_delete') {
-      $function = 'field_attach_delete_revision';
-    }
-    if (!empty($this->entityInfo['fieldable']) && function_exists($function)) {
-      $function($entity);
-    }
-    // Invoke the hook.
-    module_invoke_all($this->entityType . '_' . $hook, $entity);
-    // Invoke the respective entity-level hook.
-    module_invoke_all('entity_' . $hook, $entity, $this->entityType);
-  }
-
-  /**
    * {@inheritdoc}
    */
   public function baseFieldDefinitions() {
@@ -566,4 +549,620 @@ public function baseFieldDefinitions() {
   public function getQueryServiceName() {
     return 'entity.query.sql';
   }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function doFieldLoad($entities, $age) {
+    $load_current = $age == FIELD_LOAD_CURRENT;
+    $bundles = array();
+    $ids = $load_current ? array_keys($entities) : array();
+    foreach ($entities as $entity) {
+      $bundles[$entity->bundle()] = TRUE;
+      $ids[] = $entity->getRevisionId();
+    }
+    $fields = array();
+    foreach ($bundles as $bundle => $v) {
+      foreach ($this->fieldInfo->getBundleInstances($this->entityType, $bundle) as $field_name => $instance) {
+        $fields[$field_name] = $instance->getField();
+      }
+    }
+    foreach ($fields as $field_name => $field) {
+      $table = $load_current ? static::_fieldTableName($field) : static::_fieldRevisionTableName($field);
+
+      $results = $this->database->select($table, 't')
+        ->fields('t')
+        ->condition($load_current ? 'entity_id' : 'revision_id', $ids, 'IN')
+        ->condition('langcode', field_available_languages($this->entityType, $field), 'IN')
+        ->orderBy('delta')
+        ->condition('deleted', 0)
+        ->execute();
+
+      $delta_count = array();
+      foreach ($results as $row) {
+        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();
+          // For each column declared by the field, populate the item from the
+          // prefixed database column.
+          foreach ($field['columns'] as $column => $attributes) {
+            $column_name = static::_fieldColumnName($field, $column);
+            // Unserialize the value if specified in the column schema.
+            $item[$column] = (!empty($attributes['serialize'])) ? unserialize($row->$column_name) : $row->$column_name;
+          }
+
+          // Add the item to the field values for the entity.
+          $entities[$row->entity_id]->{$field_name}[$row->langcode][] = $item;
+          $delta_count[$row->entity_id][$row->langcode]++;
+        }
+      }
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function doFieldInsert(EntityInterface $entity) {
+    $this->doFieldWrite($entity, FALSE);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function doFieldUpdate(EntityInterface $entity) {
+    $this->doFieldWrite($entity, TRUE);
+  }
+
+  /**
+   * Performs the actual write on behalf of doFieldInsert / doFieldUpdate.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $entity
+   *   The entity being written.
+   * @param bool $update
+   *   TRUE when running an update, FALSE when running an insert.
+   */
+  protected function doFieldWrite(EntityInterface $entity, $update) {
+    $vid = $entity->getRevisionId();
+    $id = $entity->id();
+    $bundle = $entity->bundle();
+    $entity_type = $entity->entityType();
+    if (!isset($vid)) {
+      $vid = $id;
+    }
+
+    foreach ($this->fieldInfo->getBundleInstances($entity_type, $bundle) as $field_name => $instance) {
+      $field = $instance->getField();
+      $table_name = static::_fieldTableName($field);
+      $revision_name = static::_fieldRevisionTableName($field);
+
+      $all_langcodes = field_available_languages($entity_type, $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 ($update) {
+        // Delete language codes present in the incoming $entity->$field_name.
+        // Delete all language codes if $entity->$field_name is empty.
+        $langcodes = !empty($entity->$field_name) ? $field_langcodes : $all_langcodes;
+        if ($langcodes) {
+          // Only overwrite the field's base table if saving the default revision
+          // of an entity.
+          if ($entity->isDefaultRevision()) {
+            $this->database->delete($table_name)
+              ->condition('entity_id', $id)
+              ->condition('langcode', $langcodes, 'IN')
+              ->execute();
+          }
+          $this->database->delete($revision_name)
+            ->condition('entity_id', $id)
+            ->condition('revision_id', $vid)
+            ->condition('langcode', $langcodes, 'IN')
+            ->execute();
+        }
+      }
+
+      // Prepare the multi-insert query.
+      $do_insert = FALSE;
+      $columns = array('entity_id', 'revision_id', 'bundle', 'delta', 'langcode');
+      foreach ($field['columns'] as $column => $attributes) {
+        $columns[] = static::_fieldColumnName($field, $column);
+      }
+      $query = $this->database->insert($table_name)->fields($columns);
+      $revision_query = $this->database->insert($revision_name)->fields($columns);
+
+      foreach ($field_langcodes as $langcode) {
+        $items = (array) $entity->{$field_name}[$langcode];
+        $delta_count = 0;
+        foreach ($items as $delta => $item) {
+          // We now know we have someting to insert.
+          $do_insert = TRUE;
+          $record = array(
+            'entity_id' => $id,
+            'revision_id' => $vid,
+            'bundle' => $bundle,
+            'delta' => $delta,
+            'langcode' => $langcode,
+          );
+          foreach ($field['columns'] as $column => $attributes) {
+            $column_name = static::_fieldColumnName($field, $column);
+            $value = isset($item[$column]) ? $item[$column] : NULL;
+            // Serialize the value if specified in the column schema.
+            $record[$column_name] = (!empty($attributes['serialize'])) ? serialize($value) : $value;
+          }
+          $query->values($record);
+          if (isset($vid)) {
+            $revision_query->values($record);
+          }
+
+          if ($field['cardinality'] != FIELD_CARDINALITY_UNLIMITED && ++$delta_count == $field['cardinality']) {
+            break;
+          }
+        }
+      }
+
+      // Execute the query if we have values to insert.
+      if ($do_insert) {
+        // Only overwrite the field's base table if saving the default revision
+        // of an entity.
+        if ($entity->isDefaultRevision()) {
+          $query->execute();
+        }
+        $revision_query->execute();
+      }
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function doFieldDelete(EntityInterface $entity) {
+    foreach ($this->fieldInfo->getBundleInstances($entity->getType(), $entity->bundle()) as $instance) {
+      $field = $instance->getField();
+      $table_name = static::_fieldTableName($field);
+      $revision_name = static::_fieldRevisionTableName($field);
+      $this->database->delete($table_name)
+        ->condition('entity_id', $entity->id())
+        ->execute();
+      $this->database->delete($revision_name)
+        ->condition('entity_id', $entity->id())
+        ->execute();
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function doFieldRevisionDelete(EntityInterface $entity) {
+    $vid = $entity->getRevisionId();
+    if (isset($vid)) {
+      foreach ($this->fieldInfo->getBundleInstances($entity->getType(), $entity->bundle()) as $instance) {
+        $revision_name = static::_fieldRevisionTableName($instance->getField());
+        $this->database->delete($revision_name)
+          ->condition('entity_id', $entity->id())
+          ->condition('revision_id', $vid)
+          ->execute();
+      }
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function handleFieldCreate(FieldInterface $field) {
+    $schema = $this->_fieldSqlSchema($field);
+    foreach ($schema as $name => $table) {
+      $this->database->schema()->createTable($name, $table);
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function handleFieldUpdate(FieldInterface $field, FieldInterface $original) {
+    if (!$field->hasData()) {
+      // There is no data. Re-create the tables completely.
+
+      if ($this->database->supportsTransactionalDDL()) {
+        // If the database supports transactional DDL, we can go ahead and rely
+        // on it. If not, we will have to rollback manually if something fails.
+        $transaction = $this->database->startTransaction();
+      }
+
+      try {
+        $original_schema = $this->_fieldSqlSchema($original);
+        foreach ($original_schema as $name => $table) {
+          $this->database->schema()->dropTable($name, $table);
+        }
+        $schema = $this->_fieldSqlSchema($field);
+        foreach ($schema as $name => $table) {
+          $this->database->schema()->createTable($name, $table);
+        }
+      }
+      catch (\Exception $e) {
+        if ($this->database->supportsTransactionalDDL()) {
+          $transaction->rollback();
+        }
+        else {
+          // Recreate tables.
+          $original_schema = $this->_fieldSqlSchema($original);
+          foreach ($original_schema as $name => $table) {
+            if (!$this->database->schema()->tableExists($name)) {
+              $this->database->schema()->createTable($name, $table);
+            }
+          }
+        }
+        throw $e;
+      }
+    }
+    else {
+      if ($field['columns'] != $original['columns']) {
+        throw new FieldUpdateForbiddenException("The SQL storage cannot change the schema for an existing field with data.");
+      }
+      // There is data, so there are no column changes. Drop all the prior
+      // indexes and create all the new ones, except for all the priors that
+      // exist unchanged.
+      $table = static::_fieldTableName($original);
+      $revision_table = static::_fieldRevisionTableName($original);
+
+      $schema = $field->getSchema();
+      $original_schema = $original->getSchema();
+
+      foreach ($original_schema['indexes'] as $name => $columns) {
+        if (!isset($schema['indexes'][$name]) || $columns != $schema['indexes'][$name]) {
+          $real_name = static::_fieldIndexName($field, $name);
+          $this->database->schema()->dropIndex($table, $real_name);
+          $this->database->schema()->dropIndex($revision_table, $real_name);
+        }
+      }
+      $table = static::_fieldTableName($field);
+      $revision_table = static::_fieldRevisionTableName($field);
+      foreach ($schema['indexes'] as $name => $columns) {
+        if (!isset($original_schema['indexes'][$name]) || $columns != $original_schema['indexes'][$name]) {
+          $real_name = static::_fieldIndexName($field, $name);
+          $real_columns = array();
+          foreach ($columns as $column_name) {
+            // Indexes can be specified as either a column name or an array with
+            // column name and length. Allow for either case.
+            if (is_array($column_name)) {
+              $real_columns[] = array(
+                static::_fieldColumnName($field, $column_name[0]),
+                $column_name[1],
+              );
+            }
+            else {
+              $real_columns[] = static::_fieldColumnName($field, $column_name);
+            }
+          }
+          $this->database->schema()->addIndex($table, $real_name, $real_columns);
+          $this->database->schema()->addIndex($revision_table, $real_name, $real_columns);
+        }
+      }
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function handleFieldDelete(FieldInterface $field) {
+    // Mark all data associated with the field for deletion.
+    $field['deleted'] = FALSE;
+    $table = static::_fieldTableName($field);
+    $revision_table = static::_fieldRevisionTableName($field);
+    $this->database->update($table)
+      ->fields(array('deleted' => 1))
+      ->execute();
+
+    // Move the table to a unique name while the table contents are being
+    // deleted.
+    $field['deleted'] = TRUE;
+    $new_table = static::_fieldTableName($field);
+    $revision_new_table = static::_fieldRevisionTableName($field);
+    $this->database->schema()->renameTable($table, $new_table);
+    $this->database->schema()->renameTable($revision_table, $revision_new_table);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function handleInstanceDelete(FieldInstanceInterface $instance) {
+    $field = $instance->getField();
+    $table_name = static::_fieldTableName($field);
+    $revision_name = static::_fieldRevisionTableName($field);
+    $this->database->update($table_name)
+      ->fields(array('deleted' => 1))
+      ->condition('bundle', $instance['bundle'])
+      ->execute();
+    $this->database->update($revision_name)
+      ->fields(array('deleted' => 1))
+      ->condition('bundle', $instance['bundle'])
+      ->execute();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function handleBundleRename($bundle, $bundle_new) {
+    // We need to account for deleted or inactive fields and instances.
+    $instances = field_read_instances(array('entity_type' => $this->entityType, 'bundle' => $bundle_new), array('include_deleted' => TRUE, 'include_inactive' => TRUE));
+    foreach ($instances as $instance) {
+      $field = $instance->getField();
+      if ($field['storage']['type'] == 'field_sql_storage') {
+        $table_name = static::_fieldTableName($field);
+        $revision_name = static::_fieldRevisionTableName($field);
+        $this->database->update($table_name)
+          ->fields(array('bundle' => $bundle_new))
+          ->condition('bundle', $bundle)
+          ->execute();
+        $this->database->update($revision_name)
+          ->fields(array('bundle' => $bundle_new))
+          ->condition('bundle', $bundle)
+          ->execute();
+      }
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function fieldPurgeData(EntityInterface $entity, FieldInstanceInterface $instance) {
+    parent::fieldPurgeData($entity, $instance);
+    $field = $instance->getField();
+    $table_name = static::_fieldTableName($field);
+    $revision_name = static::_fieldRevisionTableName($field);
+    $this->database->delete($table_name)
+      ->condition('entity_id', $entity->id())
+      ->execute();
+    $this->database->delete($revision_name)
+      ->condition('entity_id', $entity->id())
+      ->execute();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function fieldValues(EntityInterface $entity, FieldInstanceInterface $instance) {
+    $field = $instance->getField();
+    $columns = array();
+    foreach ($field->getColumns() as $column_name => $data) {
+      $columns[] = static::_fieldColumnName($field, $column_name);
+    }
+    return $this->database->select(static::_fieldTableName($field), 't')
+      ->fields('t', $columns)
+      ->condition('entity_id', $entity->id())
+      ->execute()
+      ->fetchAll();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function fieldPurge(FieldInterface $field) {
+    $table_name = static::_fieldTableName($field);
+    $revision_name = static::_fieldRevisionTableName($field);
+    $this->database->schema()->dropTable($table_name);
+    $this->database->schema()->dropTable($revision_name);
+  }
+
+  /**
+   * Gets the SQL table schema.
+   *
+   * @private Calling this function circumvents the entity system and is
+   * strongly discouraged. This function is not considered part of the public
+   * API and modules relying on it might break even in minor releases.
+   *
+   * @param \Drupal\field\Plugin\Core\Entity\FieldInterface $field
+   *   The field object.
+   *
+   * @return array
+   *   The same as a hook_schema() implementation for the data and the
+   *   revision tables.
+   */
+  public static function _fieldSqlSchema(FieldInterface $field) {
+    $deleted = $field['deleted'] ? 'deleted ' : '';
+    $current = array(
+      'description' => "Data storage for {$deleted}field {$field['id']} ({$field['field_name']})",
+      'fields' => array(
+        'bundle' => array(
+          'type' => 'varchar',
+          'length' => 128,
+          'not null' => TRUE,
+          'default' => '',
+          'description' => 'The field instance bundle to which this row belongs, used when deleting a field instance',
+        ),
+        'deleted' => array(
+          'type' => 'int',
+          'size' => 'tiny',
+          'not null' => TRUE,
+          'default' => 0,
+          'description' => 'A boolean indicating whether this data item has been deleted'
+        ),
+        'entity_id' => array(
+          'type' => 'int',
+          'unsigned' => TRUE,
+          'not null' => TRUE,
+          'description' => 'The entity id this data is attached to',
+        ),
+        'revision_id' => array(
+          'type' => 'int',
+          'unsigned' => TRUE,
+          'not null' => FALSE,
+          'description' => 'The entity revision id this data is attached to, or NULL if the entity type is not versioned',
+        ),
+        'langcode' => array(
+          'type' => 'varchar',
+          'length' => 32,
+          'not null' => TRUE,
+          'default' => '',
+          'description' => 'The language code for this data item.',
+        ),
+        'delta' => array(
+          'type' => 'int',
+          'unsigned' => TRUE,
+          'not null' => TRUE,
+          'description' => 'The sequence number for this data item, used for multi-value fields',
+        ),
+      ),
+      'primary key' => array('entity_id', 'deleted', 'delta', 'langcode'),
+      'indexes' => array(
+        'bundle' => array('bundle'),
+        'deleted' => array('deleted'),
+        'entity_id' => array('entity_id'),
+        'revision_id' => array('revision_id'),
+        'langcode' => array('langcode'),
+      ),
+    );
+
+    $schema = $field->getSchema();
+
+    // Add field columns.
+    foreach ($schema['columns'] as $column_name => $attributes) {
+      $real_name = static::_fieldColumnName($field, $column_name);
+      $current['fields'][$real_name] = $attributes;
+    }
+
+    // Add indexes.
+    foreach ($schema['indexes'] as $index_name => $columns) {
+      $real_name = static::_fieldIndexName($field, $index_name);
+      foreach ($columns as $column_name) {
+        // Indexes can be specified as either a column name or an array with
+        // column name and length. Allow for either case.
+        if (is_array($column_name)) {
+          $current['indexes'][$real_name][] = array(
+            static::_fieldColumnName($field, $column_name[0]),
+            $column_name[1],
+          );
+        }
+        else {
+          $current['indexes'][$real_name][] = static::_fieldColumnName($field, $column_name);
+        }
+      }
+    }
+
+    // Add foreign keys.
+    foreach ($schema['foreign keys'] as $specifier => $specification) {
+      $real_name = static::_fieldIndexName($field, $specifier);
+      $current['foreign keys'][$real_name]['table'] = $specification['table'];
+      foreach ($specification['columns'] as $column_name => $referenced) {
+        $sql_storage_column = static::_fieldColumnName($field, $column_name);
+        $current['foreign keys'][$real_name]['columns'][$sql_storage_column] = $referenced;
+      }
+    }
+
+    // Construct the revision table.
+    $revision = $current;
+    $revision['description'] = "Revision archive storage for {$deleted}field {$field['id']} ({$field['field_name']})";
+    $revision['primary key'] = array('entity_id', 'revision_id', 'deleted', 'delta', 'langcode');
+    $revision['fields']['revision_id']['not null'] = TRUE;
+    $revision['fields']['revision_id']['description'] = 'The entity revision id this data is attached to';
+
+    return array(
+      static::_fieldTableName($field) => $current,
+      static::_fieldRevisionTableName($field) => $revision,
+    );
+  }
+
+  /**
+   * Generates a table name for a field data table.
+   *
+   * @private Calling this function circumvents the entity system and is
+   * strongly discouraged. This function is not considered part of the public
+   * API and modules relying on it might break even in minor releases. Only
+   * call this function to write a query that \Drupal::entityQuery() does not
+   * support. Always call entity_load() before using the data found in the
+   * table.
+   *
+   * @param $field
+   *   The field object.
+   *
+   * @return string
+   *   A string containing the generated name for the database table.
+   *
+   */
+  static public function _fieldTableName(FieldInterface $field) {
+    if ($field['deleted']) {
+      // When a field is a deleted, the table is renamed to
+      // {field_deleted_data_FIELD_UUID}. To make sure we don't end up with
+      // table names longer than 64 characters, we hash the uuid and return the
+      // first 10 characters so we end up with a short unique ID.
+      return "field_deleted_data_" . substr(hash('sha256', $field['uuid']), 0, 10);
+    }
+    else {
+      return "field_{$field['entity_type']}_{$field['field_name']}";
+    }
+  }
+
+  /**
+   * Generates a table name for a field revision archive table.
+   *
+   * @private Calling this function circumvents the entity system and is
+   * strongly discouraged. This function is not considered part of the public
+   * API and modules relying on it might break even in minor releases. Only
+   * call this function to write a query that Drupal::entityQuery() does not
+   * support. Always call entity_load() before using the data found in the
+   * table.
+   *
+   * @param \Drupal\field\Plugin\Core\Entity\FieldInterface $field
+   *   The field object.
+   *
+   * @return string
+   *   A string containing the generated name for the database table.
+   */
+  static public function _fieldRevisionTableName(FieldInterface $field) {
+    if ($field['deleted']) {
+      // When a field is a deleted, the table is renamed to
+      // {field_deleted_revision_FIELD_UUID}. To make sure we don't end up with
+      // table names longer than 64 characters, we hash the uuid and return the
+      // first 10 characters so we end up with a short unique ID.
+      return "field_deleted_revision_" . substr(hash('sha256', $field['uuid']), 0, 10);
+    }
+    else {
+      return "field_rev_{$field['entity_type']}_{$field['field_name']}";
+    }
+  }
+
+  /**
+   * Generates an index name for a field data table.
+   *
+   * @private Calling this function circumvents the entity system and is
+   * strongly discouraged. This function is not considered part of the public
+   * API and modules relying on it might break even in minor releases.
+   *
+   * @param \Drupal\field\Plugin\Core\Entity\FieldInterface $field
+   *   The field structure
+   * @param string $index
+   *   The name of the index.
+   *
+   * @return string
+   *   A string containing a generated index name for a field data table that is
+   *   unique among all other fields.
+   */
+  static public function _fieldIndexName(FieldInterface $field, $index) {
+    return $field->getFieldName() . '_' . $index;
+  }
+
+  /**
+   * Generates a column name for a field data table.
+   *
+   * @private Calling this function circumvents the entity system and is
+   * strongly discouraged. This function is not considered part of the public
+   * API and modules relying on it might break even in minor releases. Only
+   * call this function to write a query that \Drupal::entityQuery() does not
+   * support. Always call entity_load() before using the data found in the
+   * table.
+   *
+   * @param \Drupal\field\Plugin\Core\Entity\FieldInterface $field
+   *   The field object.
+   * @param string $column
+   *   The name of the column.
+   *
+   * @return string
+   *   A string containing a generated column name for a field data table that is
+   *   unique among all other fields.
+   */
+  static public function _fieldColumnName(FieldInterface $field, $column) {
+    return in_array($column, Field::getReservedColumns()) ? $column : $field->getFieldName() . '_' . $column;
+  }
+
 }
diff --git a/core/lib/Drupal/Core/Entity/DatabaseStorageControllerNG.php b/core/lib/Drupal/Core/Entity/DatabaseStorageControllerNG.php
index 143a2ab..a2bf5d6 100644
--- a/core/lib/Drupal/Core/Entity/DatabaseStorageControllerNG.php
+++ b/core/lib/Drupal/Core/Entity/DatabaseStorageControllerNG.php
@@ -8,6 +8,7 @@
 namespace Drupal\Core\Entity;
 
 use Drupal\Core\Language\Language;
+use Drupal\field\FieldInfo;
 use PDO;
 
 use Drupal\Core\Entity\Query\QueryInterface;
@@ -53,8 +54,8 @@ class DatabaseStorageControllerNG extends DatabaseStorageController {
   /**
    * Overrides DatabaseStorageController::__construct().
    */
-  public function __construct($entity_type, array $entity_info, Connection $database) {
-    parent::__construct($entity_type,$entity_info, $database);
+  public function __construct($entity_type, array $entity_info, Connection $database, FieldInfo $field_info) {
+    parent::__construct($entity_type,$entity_info, $database, $field_info);
     $this->bundleKey = !empty($this->entityInfo['entity_keys']['bundle']) ? $this->entityInfo['entity_keys']['bundle'] : FALSE;
     $this->entityClass = $this->entityInfo['class'];
 
diff --git a/core/lib/Drupal/Core/Entity/Entity.php b/core/lib/Drupal/Core/Entity/Entity.php
index 33a62ce..3959119 100644
--- a/core/lib/Drupal/Core/Entity/Entity.php
+++ b/core/lib/Drupal/Core/Entity/Entity.php
@@ -328,8 +328,7 @@ public function getTranslationLanguages($include_default = TRUE) {
       // Go through translatable properties and determine all languages for
       // which translated values are available.
       foreach (field_info_instances($this->entityType, $this->bundle()) as $field_name => $instance) {
-        $field = field_info_field($field_name);
-        if (field_is_translatable($this->entityType, $field) && isset($this->$field_name)) {
+        if (field_is_translatable($this->entityType, $instance->getField()) && isset($this->$field_name)) {
           foreach (array_filter($this->$field_name) as $langcode => $value)  {
             $languages[$langcode] = TRUE;
           }
diff --git a/core/lib/Drupal/Core/Entity/EntityFormController.php b/core/lib/Drupal/Core/Entity/EntityFormController.php
index 36fb318..057b879 100644
--- a/core/lib/Drupal/Core/Entity/EntityFormController.php
+++ b/core/lib/Drupal/Core/Entity/EntityFormController.php
@@ -295,6 +295,7 @@ protected function actions(array $form, array &$form_state) {
    */
   public function validate(array $form, array &$form_state) {
     $entity = $this->buildEntity($form, $form_state);
+    $entity_type = $entity->entityType();
     $entity_langcode = $entity->language()->id;
 
     $violations = array();
@@ -311,9 +312,9 @@ public function validate(array $form, array &$form_state) {
     else {
       // For BC entities, iterate through each field instance and
       // instantiate NG items objects manually.
-      $definitions = \Drupal::entityManager()->getFieldDefinitions($entity->entityType(), $entity->bundle());
-      foreach (field_info_instances($entity->entityType(), $entity->bundle()) as $field_name => $instance) {
-        $langcode = field_is_translatable($entity->entityType(), $instance->getField()) ? $entity_langcode : Language::LANGCODE_NOT_SPECIFIED;
+      $definitions = \Drupal::entityManager()->getFieldDefinitions($entity_type, $entity->bundle());
+      foreach (field_info_instances($entity_type, $entity->bundle()) as $field_name => $instance) {
+        $langcode = field_is_translatable($entity_type, $instance->getField()) ? $entity_langcode : Language::LANGCODE_NOT_SPECIFIED;
 
         // Create the field object.
         $items = isset($entity->{$field_name}[$langcode]) ? $entity->{$field_name}[$langcode] : array();
@@ -330,7 +331,7 @@ public function validate(array $form, array &$form_state) {
     // Map errors back to form elements.
     if ($violations) {
       foreach ($violations as $field_name => $field_violations) {
-        $langcode = field_is_translatable($entity->entityType(), field_info_field($field_name)) ? $entity_langcode : Language::LANGCODE_NOT_SPECIFIED;
+        $langcode = field_is_translatable($entity_type , field_info_field($entity_type, $field_name)) ? $entity_langcode : Language::LANGCODE_NOT_SPECIFIED;
         $field_state = field_form_get_state($form['#parents'], $field_name, $langcode, $form_state);
         $field_state['constraint_violations'] = $field_violations;
         field_form_set_state($form['#parents'], $field_name, $langcode, $form_state, $field_state);
@@ -459,8 +460,8 @@ protected function submitEntityLanguage(array $form, array &$form_state) {
       $current_langcode = $this->isDefaultFormLangcode($form_state) ? $form_state['values']['langcode'] : $this->getFormLangcode($form_state);
 
       foreach (field_info_instances($entity_type, $entity->bundle()) as $instance) {
+        $field = $instance->getField();
         $field_name = $instance['field_name'];
-        $field = field_info_field($field_name);
         $previous_langcode = $form[$field_name]['#language'];
 
         // Handle a possible language change: new language values are inserted,
diff --git a/core/lib/Drupal/Core/Entity/EntityManager.php b/core/lib/Drupal/Core/Entity/EntityManager.php
index 4766a91..4440bc6 100644
--- a/core/lib/Drupal/Core/Entity/EntityManager.php
+++ b/core/lib/Drupal/Core/Entity/EntityManager.php
@@ -88,6 +88,15 @@ class EntityManager extends PluginManagerBase {
   protected $fieldDefinitions;
 
   /**
+   * The root paths.
+   *
+   * @see \Drupal\Core\Entity\EntityManager::__construct().
+   *
+   * @var \Traversable
+   */
+  protected $namespaces;
+
+  /**
    * Constructs a new Entity plugin manager.
    *
    * @param \Traversable $namespaces
@@ -104,21 +113,45 @@ class EntityManager extends PluginManagerBase {
    */
   public function __construct(\Traversable $namespaces, ContainerInterface $container, ModuleHandlerInterface $module_handler, CacheBackendInterface $cache, LanguageManager $language_manager) {
     // Allow the plugin definition to be altered by hook_entity_info_alter().
-    $annotation_namespaces = array(
-      'Drupal\Core\Entity\Annotation' => DRUPAL_ROOT . '/core/lib',
-    );
 
     $this->moduleHandler = $module_handler;
     $this->cache = $cache;
     $this->languageManager = $language_manager;
+    $this->namespaces = $namespaces;
 
+    $this->doDiscovery($namespaces);
+    $this->factory = new DefaultFactory($this->discovery);
+    $this->container = $container;
+  }
+
+  protected function doDiscovery($namespaces) {
+    $annotation_namespaces = array(
+      'Drupal\Core\Entity\Annotation' => DRUPAL_ROOT . '/core/lib',
+    );
     $this->discovery = new AnnotatedClassDiscovery('Core/Entity', $namespaces, $annotation_namespaces, 'Drupal\Core\Entity\Annotation\EntityType');
     $this->discovery = new InfoHookDecorator($this->discovery, 'entity_info');
     $this->discovery = new AlterDecorator($this->discovery, 'entity_info');
     $this->discovery = new CacheDecorator($this->discovery, 'entity_info:' . $this->languageManager->getLanguage(Language::TYPE_INTERFACE)->id, 'cache', CacheBackendInterface::CACHE_PERMANENT, array('entity_info' => TRUE));
+  }
 
-    $this->factory = new DefaultFactory($this->discovery);
-    $this->container = $container;
+  /**
+   * Add more namespaces to the entity manager.
+   *
+   * This is usually only necessary for uninstall purposes.
+   *
+   * @todo Remove this method, along with doDiscovery(), when
+   * https://drupal.org/node/1199946 is fixed.
+   *
+   * @param \Traversable $namespaces
+   *
+   * @see comment_uninstall()
+   */
+  public function addNamespaces(\Traversable $namespaces) {
+    reset($this->namespaces);
+    $iterator = new \AppendIterator;
+    $iterator->append(new \IteratorIterator($this->namespaces));
+    $iterator->append($namespaces);
+    $this->doDiscovery($iterator);
   }
 
   /**
@@ -153,6 +186,9 @@ public function hasController($entity_type, $controller_type) {
    */
   public function getControllerClass($entity_type, $controller_type, $nested = NULL) {
     $definition = $this->getDefinition($entity_type);
+    if (!$definition) {
+      throw new \InvalidArgumentException(sprintf('The %s entity type does not exist.', $entity_type));
+    }
     $definition = $definition['controllers'];
     if (empty($definition[$controller_type])) {
       throw new \InvalidArgumentException(sprintf('The entity (%s) did not specify a %s.', $entity_type, $controller_type));
diff --git a/core/lib/Drupal/Core/Entity/EntityStorageControllerBase.php b/core/lib/Drupal/Core/Entity/EntityStorageControllerBase.php
index ea4e06c..28b4bee 100644
--- a/core/lib/Drupal/Core/Entity/EntityStorageControllerBase.php
+++ b/core/lib/Drupal/Core/Entity/EntityStorageControllerBase.php
@@ -234,6 +234,22 @@ public function invokeFieldItemPrepareCache(EntityInterface $entity) {
   }
 
   /**
+   * Invokes a hook on behalf of the entity.
+   *
+   * @param $hook
+   *   One of 'presave', 'insert', 'update', 'predelete', 'delete', or
+   *  'revision_delete'.
+   * @param \Drupal\Core\Entity\EntityInterface  $entity
+   *   The entity object.
+   */
+  protected function invokeHook($hook, EntityInterface $entity) {
+    // Invoke the hook.
+    module_invoke_all($this->entityType . '_' . $hook, $entity);
+    // Invoke the respective entity-level hook.
+    module_invoke_all('entity_' . $hook, $entity, $this->entityType);
+  }
+
+  /**
    * Checks translation statuses and invoke the related hooks if needed.
    *
    * @param \Drupal\Core\Entity\EntityInterface $entity
diff --git a/core/lib/Drupal/Core/Entity/FieldableEntityStorageControllerBase.php b/core/lib/Drupal/Core/Entity/FieldableEntityStorageControllerBase.php
new file mode 100644
index 0000000..9ff2823
--- /dev/null
+++ b/core/lib/Drupal/Core/Entity/FieldableEntityStorageControllerBase.php
@@ -0,0 +1,330 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Entity\FieldableEntityStorageControllerBase.
+ */
+
+
+namespace Drupal\Core\Entity;
+
+use Drupal\field\FieldInterface;
+use Drupal\field\FieldInstanceInterface;
+use Symfony\Component\DependencyInjection\Container;
+
+abstract class FieldableEntityStorageControllerBase extends EntityStorageControllerBase implements FieldableEntityStorageControllerInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function invokeHook($hook, EntityInterface $entity) {
+    $method = Container::camelize('field_' . $hook);
+    if (!empty($this->entityInfo['fieldable']) && method_exists($this, $method)) {
+      $this->$method($entity);
+    }
+    parent::invokeHook($hook, $entity);
+  }
+
+  /**
+   * Loads fields for the current revisions of a group of entities.
+   *
+   * Loads all fields for each entity object in a group of a single entity type.
+   * The loaded field values are added directly to the entity objects.
+   *
+   * @param $entities
+   *   An array of entities for which to load fields, keyed by entity ID.
+   * @param $age
+   *   FIELD_LOAD_CURRENT to load the most recent revision for all fields, or
+   *   FIELD_LOAD_REVISION to load the version indicated by each entity.
+   */
+  protected function fieldLoad($entities, $age) {
+    if (empty($entities)) {
+      return;
+    }
+
+    // Only the most current revision of non-deleted fields for cacheable entity
+    // types can be cached.
+    $load_current = $age == FIELD_LOAD_CURRENT;
+    $info = entity_get_info($this->entityType);
+    $use_cache = $load_current && $info['field_cache'];
+
+    // Ensure we are working with a BC mode entity.
+    foreach ($entities as $id => $entity) {
+      $entities[$id] = $entity->getBCEntity();
+    }
+
+    // Assume all entities will need to be queried. Entities found in the cache
+    // will be removed from the list.
+    $queried_entities = $entities;
+
+    // Fetch available entities from cache, if applicable.
+    if ($use_cache) {
+      // Build the list of cache entries to retrieve.
+      $cids = array();
+      foreach ($entities as $id => $entity) {
+        $cids[] = "field:$this->entityType:$id";
+      }
+      $cache = cache('field')->getMultiple($cids);
+      // Put the cached field values back into the entities and remove them from
+      // the list of entities to query.
+      foreach ($entities as $id => $entity) {
+        $cid = "field:$this->entityType:$id";
+        if (isset($cache[$cid])) {
+          unset($queried_entities[$id]);
+          foreach ($cache[$cid]->data as $field_name => $values) {
+            $entity->$field_name = $values;
+          }
+        }
+      }
+    }
+
+    // Fetch other entities from their storage location.
+    if ($queried_entities) {
+      // The invoke order is:
+      // - hook_field_storage_pre_load()
+      // - Entity storage controller's doFieldLoad() method
+      // - Field class's prepareCache() method.
+      // - hook_field_attach_load()
+
+      // Invoke hook_field_storage_pre_load(): let any module load field data
+      // before the storage engine, accumulating along the way.
+      foreach (module_implements('field_storage_pre_load') as $module) {
+        $function = $module . '_field_storage_pre_load';
+        $function($this->entityType, $queried_entities, $age);
+      }
+
+      // Let the storage controller actually load the values.
+      $this->doFieldLoad($queried_entities, $age);
+
+      // Invoke the field type's prepareCache() method.
+      foreach ($queried_entities as $entity) {
+        \Drupal::entityManager()
+          ->getStorageController($this->entityType)
+          ->invokeFieldItemPrepareCache($entity);
+      }
+
+      // Invoke hook_field_attach_load(): let other modules act on loading the
+      // entity.
+      module_invoke_all('field_attach_load', $this->entityType, $queried_entities, $age);
+
+      // Build cache data.
+      if ($use_cache) {
+        foreach ($queried_entities as $id => $entity) {
+          $data = array();
+          $instances = field_info_instances($this->entityType, $entity->bundle());
+          foreach ($instances as $instance) {
+            $data[$instance['field_name']] = $queried_entities[$id]->{$instance['field_name']};
+          }
+          $cid = "field:$this->entityType:$id";
+          cache('field')->set($cid, $data);
+        }
+      }
+    }
+  }
+
+  /**
+   * Save field data for a new entity.
+   *
+   * The passed-in entity must already contain its id and (if applicable)
+   * revision id attributes.
+   *
+   * It should be enough to override doFieldInsert() instead of this method.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $entity
+   *   The entity with fields to save.
+   * @return
+   *   Default values (if any) will be added to the $entity parameter for fields
+   *   it leaves unspecified.
+   */
+  protected function fieldInsert(EntityInterface $entity) {
+    // Ensure we are working with a BC mode entity.
+    $entity = $entity->getBCEntity();
+
+    // Let any module insert field data before the storage engine.
+    foreach (module_implements('field_storage_pre_insert') as $module) {
+      $function = $module . '_field_storage_pre_insert';
+      $function($entity);
+    }
+    $this->doFieldInsert($entity);
+  }
+
+  /**
+   * Saves field data for an existing entity.
+   *
+   * It should be enough to override doFieldUpdate() instead of this method.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $entity
+   *   The entity with fields to save.
+   */
+  protected function fieldUpdate(EntityInterface $entity) {
+    // Ensure we are working with a BC mode entity.
+    $entity = $entity->getBCEntity();
+
+    // Let any module update field data before the storage engine
+    foreach (module_implements('field_storage_pre_update') as $module) {
+      $function = $module . '_field_storage_pre_update';
+      $function($entity);
+    }
+
+    $this->doFieldUpdate($entity);
+
+    $entity_info = $entity->entityInfo();
+    if ($entity_info['field_cache']) {
+      cache('field')->delete('field:' . $entity->entityType() . ':' . $entity->id());
+    }
+  }
+
+  /**
+   * Deletes field data for an existing entity. This deletes all revisions of
+   * field data for the entity.
+   *
+   * It should be enough to override doFieldDelete() instead of this method.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $entity
+   *   The entity whose field data to delete.
+   */
+  protected function fieldDelete(EntityInterface $entity) {
+    // Ensure we are working with a BC mode entity.
+    $entity = $entity->getBCEntity();
+
+    $this->doFieldDelete($entity);
+
+    $entity_info = $entity->entityInfo();
+    if ($entity_info['field_cache']) {
+      cache('field')->delete('field:' . $entity->entityType() . ':' . $entity->id());
+    }
+  }
+
+  /**
+   * Delete field data for a single revision of an existing entity. The passed
+   * entity must have a revision ID attribute.
+   *
+   * It should be enough to override doFieldRevisionDelete() instead of this
+   * method.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $entity
+   *   The entity with fields to save.
+   */
+  protected function fieldRevisionDelete(EntityInterface $entity) {
+    $this->dofieldRevisionDelete($entity->getBCEntity());
+  }
+
+  /**
+   * Load configurable fields from storage.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $entity
+   *   The entity.
+   */
+  protected function doFieldLoad($queried_entities, $age) { }
+
+  /**
+   * Insert configurable fields into storage.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $entity
+   *   The entity.
+   */
+  protected function doFieldInsert(EntityInterface $entity) { }
+
+  /**
+   * Update configurable fields in storage.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $entity
+   *   The entity.
+   */
+  protected function doFieldUpdate(EntityInterface $entity) { }
+
+  /**
+   * Delete configurable fields from storage.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $entity
+   *   The entity.
+   */
+  protected function doFieldDelete(EntityInterface $entity) { }
+
+  /**
+   * Delete specific revision of configurable fields from storage.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $entity
+   *   The entity.
+   */
+  protected function doFieldRevisionDelete(EntityInterface $entity) { }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function handleFieldCreate(FieldInterface $field) { }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function handleFieldUpdate(FieldInterface $field, FieldInterface $original) { }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function handleFieldDelete(FieldInterface $field) { }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function handleInstanceCreate(FieldInstanceInterface $instance) { }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function handleInstanceUpdate(FieldInstanceInterface $instance, FieldInstanceInterface $orignal) { }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function handleInstanceDelete(FieldInstanceInterface $instance) { }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function handleBundleCreate($bundle) { }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function handleBundleRename($bundle, $bundle_new) { }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function handleBundleDelete($bundle) { }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function fieldPurgeData(EntityInterface $entity, FieldInstanceInterface $instance) {
+    $values = $this->fieldValues($entity, $instance);
+    $field = $instance->getField();
+    foreach ($values as $value) {
+      $definition = _field_generate_entity_field_definition($field, $instance);
+      $items = \Drupal::typedData()->create($definition, $value, $field->getFieldName(), $entity);
+      $items->delete();
+    }
+  }
+
+  /**
+   * Gets the field values for a single field of a single entity.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $entity
+   *   The entity.
+   * @param \Drupal\field\FieldInstanceInterface $instance
+   *   The field instance.
+   *
+   * @return array
+   *   The field values.
+   */
+  protected function fieldValues(EntityInterface $entity, FieldInstanceInterface $instance) {
+    return array();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function fieldPurge(FieldInterface $field) { }
+
+}
diff --git a/core/lib/Drupal/Core/Entity/FieldableEntityStorageControllerInterface.php b/core/lib/Drupal/Core/Entity/FieldableEntityStorageControllerInterface.php
new file mode 100644
index 0000000..71cb93d
--- /dev/null
+++ b/core/lib/Drupal/Core/Entity/FieldableEntityStorageControllerInterface.php
@@ -0,0 +1,106 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Entity\ExtensibleEntityStorageControllerInterface.
+ */
+
+
+namespace Drupal\Core\Entity;
+
+
+use Drupal\field\FieldInterface;
+use Drupal\field\FieldInstanceInterface;
+
+interface FieldableEntityStorageControllerInterface extends EntityStorageControllerInterface {
+
+  /**
+   * Allows reaction to the update of a configurable field.
+   *
+   * @param \Drupal\field\FieldInterface $field
+   *   The field being updated.
+   * @param \Drupal\field\FieldInterface $original
+   *   The previous state of the field.
+   */
+  public function handleFieldUpdate(FieldInterface $field, FieldInterface $original);
+
+  /**
+   * Allows reaction to the deletion of a configurable field.
+   *
+   * @param \Drupal\field\FieldInterface $field
+   *   The field being deleted.
+   */
+  public function handleFieldDelete(FieldInterface $field);
+
+  /**
+   * Allows reaction to the creation of a configurable field.
+   *
+   * @param \Drupal\field\FieldInterface $field
+   *   The field being created.
+   */
+  public function handleFieldCreate(FieldInterface $field);
+
+  /**
+   * Allows reaction to the creation of a configurable field instance.
+   *
+   * @param \Drupal\field\FieldInstanceInterface $instance
+   *   The instance being created.
+   */
+  public function handleInstanceCreate(FieldInstanceInterface $instance);
+
+  /**
+   * Allows reaction to the deletion of a configurable field instance.
+   *
+   * @param \Drupal\field\FieldInstanceInterface $instance
+   *   The instance being deleted.
+   */
+  public function handleInstanceDelete(FieldInstanceInterface $instance);
+
+  /**
+   * Allows reaction to a bundle being created.
+   *
+   * @param string $bundle
+   *   The name of the bundle created.
+   */
+  public function handleBundleCreate($bundle);
+
+  /**
+   * Allows reaction to a bundle being renamed.
+   *
+   * @param string $bundle
+   *   The name of the bundle being renamed.
+   * @param string $bundle_new
+   *   The new name of the bundle.
+   */
+  public function handleBundleRename($bundle, $bundle_new);
+
+  /**
+   * Allows reaction to a bundle being deleted.
+   *
+   * @param string $bundle
+   *   The name of the bundle being deleted.
+   */
+  public function handleBundleDelete($bundle);
+
+  /**
+   * Purges the field data for a single field on a single entity.
+   *
+   * The entity itself is not being deleted, and it is quite possible that
+   * other field data will remain attached to it.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $entity
+   *   The entity whose field data is being purged.
+   * @param \Drupal\field\FieldInstanceInterface $instance
+   *   The deleted field instance whose data is being purged.
+   */
+  public function fieldPurgeData(EntityInterface $entity, FieldInstanceInterface $instance);
+
+  /**
+   * Performs final cleanup after all data on all instances have been purged.
+   *
+   * @param \Drupal\field\FieldInterface $instance
+   *   The field being purged.
+   */
+  public function fieldPurge(FieldInterface $field);
+
+}
diff --git a/core/lib/Drupal/Core/Entity/Query/Sql/Tables.php b/core/lib/Drupal/Core/Entity/Query/Sql/Tables.php
index 2f7156a..1d89125 100644
--- a/core/lib/Drupal/Core/Entity/Query/Sql/Tables.php
+++ b/core/lib/Drupal/Core/Entity/Query/Sql/Tables.php
@@ -8,6 +8,7 @@
 namespace Drupal\Core\Entity\Query\Sql;
 
 use Drupal\Core\Database\Query\SelectInterface;
+use Drupal\Core\Entity\DatabaseStorageController;
 use Drupal\Core\Entity\Plugin\DataType\EntityReference;
 use Drupal\Core\Entity\Query\QueryException;
 use Drupal\field\Plugin\Core\Entity\Field;
@@ -108,7 +109,7 @@ function addField($field, $type, $langcode) {
         $field = field_info_field_by_id(substr($specifier, 3));
       }
       elseif (isset($field_map[$specifier])) {
-        $field = field_info_field($specifier);
+        $field = field_info_field($entity_type, $specifier);
       }
       else {
         $field = FALSE;
@@ -157,7 +158,7 @@ function addField($field, $type, $langcode) {
           $column = 'value';
         }
         $table = $this->ensureFieldTable($index_prefix, $field, $type, $langcode, $base_table, $entity_id_field, $field_id_field);
-        $sql_column = _field_sql_storage_columnname($field['field_name'], $column);
+        $sql_column = DatabaseStorageController::_fieldColumnName($field, $column);
       }
       // This is an entity property (non-configurable field).
       else {
@@ -242,12 +243,12 @@ protected function ensureEntityTable($index_prefix, $property, $type, $langcode,
   protected function ensureFieldTable($index_prefix, &$field, $type, $langcode, $base_table, $entity_id_field, $field_id_field) {
     $field_name = $field['field_name'];
     if (!isset($this->fieldTables[$index_prefix . $field_name])) {
-      $table = $this->sqlQuery->getMetaData('age') == FIELD_LOAD_CURRENT ? _field_sql_storage_tablename($field) : _field_sql_storage_revision_tablename($field);
+      $table = $this->sqlQuery->getMetaData('age') == FIELD_LOAD_CURRENT ? DatabaseStorageController::_fieldTableName($field) : DatabaseStorageController::_fieldRevisionTableName($field);
       if ($field['cardinality'] != 1) {
         $this->sqlQuery->addMetaData('simple_query', FALSE);
       }
       $entity_type = $this->sqlQuery->getMetaData('entity_type');
-      $this->fieldTables[$index_prefix . $field_name] = $this->addJoin($type, $table, "%alias.$field_id_field = $base_table.$entity_id_field AND %alias.entity_type = '$entity_type'", $langcode);
+      $this->fieldTables[$index_prefix . $field_name] = $this->addJoin($type, $table, "%alias.$field_id_field = $base_table.$entity_id_field", $langcode);
     }
     return $this->fieldTables[$index_prefix . $field_name];
   }
diff --git a/core/modules/block/custom_block/custom_block.module b/core/modules/block/custom_block/custom_block.module
index 4e55a85..9183c54 100644
--- a/core/modules/block/custom_block/custom_block.module
+++ b/core/modules/block/custom_block/custom_block.module
@@ -176,13 +176,13 @@ function custom_block_entity_bundle_info() {
  */
 function custom_block_add_body_field($block_type_id, $label = 'Block body') {
   // Add or remove the body field, as needed.
-  $field = field_info_field('block_body');
+  $field = field_info_field('custom_block', 'block_body');
   $instance = field_info_instance('custom_block', 'block_body', $block_type_id);
   if (empty($field)) {
     $field = entity_create('field_entity', array(
-      'field_name' => 'block_body',
+      'name' => 'block_body',
+      'entity_type' => 'custom_block',
       'type' => 'text_with_summary',
-      'entity_types' => array('custom_block'),
     ));
     $field->save();
   }
diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockStorageController.php b/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockStorageController.php
index 0698234..5fb5330 100644
--- a/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockStorageController.php
+++ b/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockStorageController.php
@@ -16,7 +16,7 @@
  * This extends the Drupal\Core\Entity\DatabaseStorageControllerNG class,
  * adding required special handling for custom block entities.
  */
-class CustomBlockStorageController extends DatabaseStorageControllerNG implements EntityStorageControllerInterface {
+class CustomBlockStorageController extends DatabaseStorageControllerNG {
 
   /**
    * Overrides \Drupal\Core\Entity\DatabaseStorageController::attachLoad().
diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/Tests/CustomBlockFieldTest.php b/core/modules/block/custom_block/lib/Drupal/custom_block/Tests/CustomBlockFieldTest.php
index da5ac4f..0466568 100644
--- a/core/modules/block/custom_block/lib/Drupal/custom_block/Tests/CustomBlockFieldTest.php
+++ b/core/modules/block/custom_block/lib/Drupal/custom_block/Tests/CustomBlockFieldTest.php
@@ -65,13 +65,14 @@ public function testBlockFields() {
 
     // Create a field with settings to validate.
     $this->field = entity_create('field_entity', array(
-      'field_name' => drupal_strtolower($this->randomName()),
+      'name' => drupal_strtolower($this->randomName()),
+      'entity_type' => 'custom_block',
       'type' => 'link',
       'cardinality' => 2,
     ));
     $this->field->save();
     $this->instance = entity_create('field_instance', array(
-      'field_name' => $this->field->id(),
+      'field_name' => $this->field->getFieldName(),
       'entity_type' => 'custom_block',
       'bundle' => 'link',
       'settings' => array(
diff --git a/core/modules/comment/comment.install b/core/modules/comment/comment.install
index efaf9f3..04e1291 100644
--- a/core/modules/comment/comment.install
+++ b/core/modules/comment/comment.install
@@ -12,6 +12,10 @@ function comment_uninstall() {
   // Remove variables.
   variable_del('comment_block_count');
   $node_types = array_keys(node_type_get_types());
+  Drupal::entityManager()->addNamespaces(new ArrayIterator(array(
+    'Drupal\comment' => DRUPAL_ROOT . '/core/modules/comment/lib',
+  )));
+  drupal_classloader_register('comment', 'core/modules/comment');
   foreach ($node_types as $node_type) {
     entity_invoke_bundle_hook('delete', 'comment', 'comment_node_' . $node_type);
     variable_del('comment_' . $node_type);
diff --git a/core/modules/comment/comment.module b/core/modules/comment/comment.module
index f436966..7bfed58 100644
--- a/core/modules/comment/comment.module
+++ b/core/modules/comment/comment.module
@@ -324,9 +324,9 @@ function _comment_body_field_create($info) {
   // Create the field if needed.
   if (!field_read_field('comment_body', array('include_inactive' => TRUE))) {
     $field = entity_create('field_entity', array(
-      'field_name' => 'comment_body',
+      'name' => 'comment_body',
       'type' => 'text_long',
-      'entity_types' => array('comment'),
+      'entity_type' => 'comment',
     ));
     $field->save();
   }
diff --git a/core/modules/comment/lib/Drupal/comment/Tests/CommentFieldsTest.php b/core/modules/comment/lib/Drupal/comment/Tests/CommentFieldsTest.php
index ecd464a..c3c9047 100644
--- a/core/modules/comment/lib/Drupal/comment/Tests/CommentFieldsTest.php
+++ b/core/modules/comment/lib/Drupal/comment/Tests/CommentFieldsTest.php
@@ -45,7 +45,7 @@ function testCommentDefaultFields() {
     }
 
     // Check that the 'comment_body' field is deleted.
-    $field = field_info_field('comment_body');
+    $field = field_info_field('comment', 'comment_body');
     $this->assertTrue(empty($field), 'The comment_body field was deleted');
 
     // Create a new content type.
@@ -54,7 +54,7 @@ function testCommentDefaultFields() {
 
     // Check that the 'comment_body' field exists and has an instance on the
     // new comment bundle.
-    $field = field_info_field('comment_body');
+    $field = field_info_field('comment', 'comment_body');
     $this->assertTrue($field, 'The comment_body field exists');
     $instances = field_info_instances('comment');
     $this->assertTrue(isset($instances['comment_node_' . $type_name]['comment_body']), format_string('The comment_body field is present for comments on type @type', array('@type' => $type_name)));
diff --git a/core/modules/comment/lib/Drupal/comment/Tests/CommentLanguageTest.php b/core/modules/comment/lib/Drupal/comment/Tests/CommentLanguageTest.php
index 1e443ac..6792d8d 100644
--- a/core/modules/comment/lib/Drupal/comment/Tests/CommentLanguageTest.php
+++ b/core/modules/comment/lib/Drupal/comment/Tests/CommentLanguageTest.php
@@ -71,7 +71,7 @@ function setUp() {
     $this->drupalPost("user/" . $admin_user->id() . "/edit", $edit, t('Save'));
 
     // Make comment body translatable.
-    $field = field_info_field('comment_body');
+    $field = field_info_field('comment', 'comment_body');
     $field['translatable'] = TRUE;
     $field->save();
     $this->assertTrue(field_is_translatable('comment', $field), 'Comment body is translatable.');
diff --git a/core/modules/comment/lib/Drupal/comment/Tests/CommentTranslationUITest.php b/core/modules/comment/lib/Drupal/comment/Tests/CommentTranslationUITest.php
index 49d6814..9133ea9 100644
--- a/core/modules/comment/lib/Drupal/comment/Tests/CommentTranslationUITest.php
+++ b/core/modules/comment/lib/Drupal/comment/Tests/CommentTranslationUITest.php
@@ -63,7 +63,7 @@ protected function getTranslatorPermissions() {
    */
   function setupTestFields() {
     parent::setupTestFields();
-    $field = field_info_field('comment_body');
+    $field = field_info_field('comment', 'comment_body');
     $field['translatable'] = TRUE;
     $field->save();
   }
diff --git a/core/modules/comment/lib/Drupal/comment/Tests/CommentUninstallTest.php b/core/modules/comment/lib/Drupal/comment/Tests/CommentUninstallTest.php
index 48e749f..127a611 100644
--- a/core/modules/comment/lib/Drupal/comment/Tests/CommentUninstallTest.php
+++ b/core/modules/comment/lib/Drupal/comment/Tests/CommentUninstallTest.php
@@ -42,7 +42,7 @@ protected function setUp() {
    */
   function testCommentUninstallWithField() {
     // Ensure that the field exists before uninstallation.
-    $field = field_info_field('comment_body');
+    $field = field_info_field('comment', 'comment_body');
     $this->assertNotNull($field, 'The comment_body field exists.');
 
     // Uninstall the comment module which should trigger field deletion.
@@ -50,7 +50,7 @@ function testCommentUninstallWithField() {
     $this->container->get('module_handler')->uninstall(array('comment'));
 
     // Check that the field is now deleted.
-    $field = field_info_field('comment_body');
+    $field = field_info_field('comment', 'comment_body');
     $this->assertNull($field, 'The comment_body field has been deleted.');
   }
 
@@ -60,12 +60,12 @@ function testCommentUninstallWithField() {
    */
   function testCommentUninstallWithoutField() {
     // Manually delete the comment_body field before module uninstallation.
-    $field = field_info_field('comment_body');
+    $field = field_info_field('comment', 'comment_body');
     $this->assertNotNull($field, 'The comment_body field exists.');
     $field->delete();
 
     // Check that the field is now deleted.
-    $field = field_info_field('comment_body');
+    $field = field_info_field('comment', 'comment_body');
     $this->assertNull($field, 'The comment_body field has been deleted.');
 
     // Ensure that uninstallation succeeds even if the field has already been
diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigLocaleOverride.php b/core/modules/config/lib/Drupal/config/Tests/ConfigLocaleOverride.php
index 79f22a9..6d4ff98 100644
--- a/core/modules/config/lib/Drupal/config/Tests/ConfigLocaleOverride.php
+++ b/core/modules/config/lib/Drupal/config/Tests/ConfigLocaleOverride.php
@@ -21,7 +21,7 @@ class ConfigLocaleOverride extends DrupalUnitTestBase {
    *
    * @var array
    */
-  public static $modules = array('locale', 'config_test', 'user', 'language', 'system');
+  public static $modules = array('locale', 'config_test', 'user', 'language', 'system', 'field');
 
   public static function getInfo() {
     return array(
diff --git a/core/modules/contact/lib/Drupal/contact/Tests/MessageEntityTest.php b/core/modules/contact/lib/Drupal/contact/Tests/MessageEntityTest.php
index c9e2e5d..271acfd 100644
--- a/core/modules/contact/lib/Drupal/contact/Tests/MessageEntityTest.php
+++ b/core/modules/contact/lib/Drupal/contact/Tests/MessageEntityTest.php
@@ -21,7 +21,7 @@ class MessageEntityTest extends DrupalUnitTestBase {
    *
    * @var array
    */
-  public static $modules = array('system', 'contact');
+  public static $modules = array('system', 'contact', 'field');
 
   public static function getInfo() {
     return array(
diff --git a/core/modules/contact/lib/Drupal/contact/Tests/Views/ContactFieldsTest.php b/core/modules/contact/lib/Drupal/contact/Tests/Views/ContactFieldsTest.php
index 166a64b..1379a24 100644
--- a/core/modules/contact/lib/Drupal/contact/Tests/Views/ContactFieldsTest.php
+++ b/core/modules/contact/lib/Drupal/contact/Tests/Views/ContactFieldsTest.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\contact\Tests\Views;
 
+use Drupal\Core\Entity\DatabaseStorageController;
 use Drupal\views\Tests\ViewTestBase;
 
 /**
@@ -40,7 +41,8 @@ protected function setUp() {
     parent::setUp();
 
     $this->field = entity_create('field_entity', array(
-      'field_name' => strtolower($this->randomName()),
+      'name' => strtolower($this->randomName()),
+      'entity_type' => 'contact_message',
       'type' => 'text'
     ));
     $this->field->save();
@@ -58,7 +60,7 @@ protected function setUp() {
    * Tests the views data generation.
    */
   public function testViewsData() {
-    $table_name = _field_sql_storage_tablename($this->field);
+    $table_name = DatabaseStorageController::_fieldTableName($this->field);
     $data = $this->container->get('views.views_data')->get($table_name);
 
     // Test that the expected data array is returned.
diff --git a/core/modules/content_translation/content_translation.admin.inc b/core/modules/content_translation/content_translation.admin.inc
index 63e71fc..a4186ba 100644
--- a/core/modules/content_translation/content_translation.admin.inc
+++ b/core/modules/content_translation/content_translation.admin.inc
@@ -95,7 +95,7 @@ function _content_translation_form_language_content_settings_form_alter(array &$
           // @todo Exploit field definitions once all core entities and field
           // types are migrated to the Entity Field API.
           foreach ($fields as $field_name => $instance) {
-            $field = field_info_field($field_name);
+            $field = $instance->getField();
             $form['settings'][$entity_type][$bundle]['fields'][$field_name] = array(
               '#label' => $instance['label'],
               '#type' => 'checkbox',
@@ -326,7 +326,7 @@ function _content_translation_update_field_translatability($settings) {
         foreach ($bundle_settings['fields'] as $field_name => $translatable) {
           // If a field is enabled for translation for at least one instance we
           // need to mark it as translatable.
-          $fields[$field_name] = $translatable || !empty($fields[$field_name]);
+          $fields[$entity_type][$field_name] = $translatable || !empty($fields[$entity_type][$field_name]);
         }
       }
       // @todo Store non-configurable field settings to be able to alter their
@@ -335,22 +335,24 @@ function _content_translation_update_field_translatability($settings) {
   }
 
   $operations = array();
-  foreach ($fields as $field_name => $translatable) {
-    $field = field_info_field($field_name);
-    if ($field['translatable'] != $translatable) {
-      // If a field is untranslatable, it can have no data except under
-      // Language::LANGCODE_NOT_SPECIFIED. Thus we need a field to be translatable before
-      // we convert data to the entity language. Conversely we need to switch
-      // data back to Language::LANGCODE_NOT_SPECIFIED before making a field
-      // untranslatable lest we lose information.
-      $field_operations = array(
-        array('content_translation_translatable_switch', array($translatable, $field_name)),
-      );
-      if ($field->hasData()) {
-        $field_operations[] = array('content_translation_translatable_batch', array($translatable, $field_name));
-        $field_operations = $translatable ? $field_operations : array_reverse($field_operations);
+  foreach ($fields as $entity_type => $entity_type_fields) {
+    foreach ($entity_type_fields as $field_name => $translatable) {
+      $field = field_info_field($entity_type, $field_name);
+      if ($field['translatable'] != $translatable) {
+        // If a field is untranslatable, it can have no data except under
+        // Language::LANGCODE_NOT_SPECIFIED. Thus we need a field to be translatable before
+        // we convert data to the entity language. Conversely we need to switch
+        // data back to Language::LANGCODE_NOT_SPECIFIED before making a field
+        // untranslatable lest we lose information.
+        $field_operations = array(
+          array('content_translation_translatable_switch', array($translatable, $entity_type, $field_name)),
+        );
+        if ($field->hasData()) {
+          $field_operations[] = array('content_translation_translatable_batch', array($translatable, $field_name));
+          $field_operations = $translatable ? $field_operations : array_reverse($field_operations);
+        }
+        $operations = array_merge($operations, $field_operations);
       }
-      $operations = array_merge($operations, $field_operations);
     }
   }
 
@@ -374,11 +376,13 @@ function _content_translation_update_field_translatability($settings) {
  * @param bool $translatable
  *   Indicator of whether the field should be made translatable (TRUE) or
  *   untranslatble (FALSE).
+ * @param string $entity_type
+ *   Field entity type.
  * @param string $field_name
  *   Field machine name.
  */
-function content_translation_translatable_switch($translatable, $field_name) {
-  $field = field_info_field($field_name);
+function content_translation_translatable_switch($translatable, $entity_type, $field_name) {
+  $field = field_info_field($entity_type, $field_name);
   if ($field['translatable'] !== $translatable) {
     $field['translatable'] = $translatable;
     $field->save();
@@ -395,10 +399,6 @@ function content_translation_translatable_switch($translatable, $field_name) {
  *   Field machine name.
  */
 function content_translation_translatable_batch($translatable, $field_name, &$context) {
-  $field = field_info_field($field_name);
-  $column = isset($field['columns']['value']) ? 'value' : key($field['columns']);
-  $query_field = "$field_name.$column";
-
   // Determine the entity types to act on.
   $entity_types = array();
   foreach (field_info_instances() as $entity_type => $info) {
@@ -417,6 +417,10 @@ function content_translation_translatable_batch($translatable, $field_name, &$co
     $context['sandbox']['max'] = 0;
 
     foreach ($entity_types as $entity_type) {
+      $field = field_info_field($entity_type, $field_name);
+      $column = isset($field['columns']['value']) ? 'value' : key($field['columns']);
+      $query_field = "$field_name.$column";
+
       // How many entities will need processing?
       $query = Drupal::entityQuery($entity_type);
       $count = $query
@@ -444,6 +448,9 @@ function content_translation_translatable_batch($translatable, $field_name, &$co
     $info = entity_get_info($entity_type);
     $offset = $context['sandbox']['progress_entity_type'][$entity_type];
     $query = Drupal::entityQuery($entity_type);
+    $field = field_info_field($entity_type, $field_name);
+    $column = isset($field['columns']['value']) ? 'value' : key($field['columns']);
+    $query_field = "$field_name.$column";
     $result = $query
       ->exists($query_field)
       ->sort($info['entity_keys']['id'])
diff --git a/core/modules/content_translation/content_translation.module b/core/modules/content_translation/content_translation.module
index a6988cf..86f8d76 100644
--- a/core/modules/content_translation/content_translation.module
+++ b/core/modules/content_translation/content_translation.module
@@ -200,7 +200,7 @@ function content_translation_menu() {
     }
   }
 
-  $items['admin/config/regional/content_translation/translatable/%'] = array(
+  $items['admin/config/regional/content_translation/translatable/%/%'] = array(
     'title' => 'Confirm change in translatability.',
     'description' => 'Confirm page for changing field translatability.',
     'route_name' => 'content_translation_translatable',
@@ -621,7 +621,7 @@ function content_translation_form_alter(array &$form, array &$form_state) {
       else {
         foreach (field_info_instances($entity->entityType(), $entity->bundle()) as $instance) {
           $field_name = $instance['field_name'];
-          $field = field_info_field($field_name);
+          $field = $instance->getField();
           $form[$field_name]['#multilingual'] = !empty($field['translatable']);
         }
       }
@@ -808,6 +808,7 @@ function content_translation_field_extra_fields() {
  */
 function content_translation_form_field_ui_field_edit_form_alter(array &$form, array &$form_state, $form_id) {
   $field = $form['#field'];
+  $entity_type = $field['entity_type'];
   $field_name = $field['field_name'];
   $translatable = $field['translatable'];
   $label = t('Field translation');
@@ -821,7 +822,7 @@ function content_translation_form_field_ui_field_edit_form_alter(array &$form, a
         '#type' => 'link',
         '#prefix' => t('This field has data in existing content.') . ' ',
         '#title' => !$translatable ? t('Enable translation') : t('Disable translation'),
-        '#href' => 'admin/config/regional/content_translation/translatable/' . $field_name,
+        '#href' => "admin/config/regional/content_translation/translatable/$entity_type/$field_name",
         '#options' => array('query' => drupal_get_destination()),
         '#access' => user_access('administer content translation'),
       ),
@@ -1022,7 +1023,7 @@ function content_translation_save_settings($settings) {
         // Store whether fields have translation enabled or not.
         if (!empty($bundle_settings['columns'])) {
           foreach ($bundle_settings['columns'] as $field_name => $column_settings) {
-            $field = field_info_field($field_name);
+            $field = field_info_field($entity_type, $field_name);
             $instance = field_info_instance($entity_type, $field_name, $bundle);
             if ($field['translatable']) {
               $instance['settings']['translation_sync'] = $column_settings;
diff --git a/core/modules/content_translation/content_translation.pages.inc b/core/modules/content_translation/content_translation.pages.inc
index e277791..966d259 100644
--- a/core/modules/content_translation/content_translation.pages.inc
+++ b/core/modules/content_translation/content_translation.pages.inc
@@ -40,8 +40,7 @@ function content_translation_overview(EntityInterface $entity) {
     // Determine whether the current entity is translatable.
     $translatable = FALSE;
     foreach (field_info_instances($entity->entityType(), $entity->bundle()) as $instance) {
-      $field_name = $instance['field_name'];
-      $field = field_info_field($field_name);
+      $field = $instance->getField();
       if ($field['translatable']) {
         $translatable = TRUE;
         break;
@@ -246,7 +245,7 @@ function content_translation_prepare_translation(EntityInterface $entity, Langua
   else {
     $instances = field_info_instances($entity->entityType(), $entity->bundle());
     foreach ($instances as $field_name => $instance) {
-      $field = field_info_field($field_name);
+      $field = $instance->getField();
       if (!empty($field['translatable'])) {
         $value = $entity->get($field_name);
         $value[$target->id] = isset($value[$source->id]) ? $value[$source->id] : array();
diff --git a/core/modules/content_translation/content_translation.routing.yml b/core/modules/content_translation/content_translation.routing.yml
index d7d55a1..64f210c 100644
--- a/core/modules/content_translation/content_translation.routing.yml
+++ b/core/modules/content_translation/content_translation.routing.yml
@@ -1,5 +1,5 @@
 content_translation_translatable:
-  pattern: 'admin/config/regional/content_translation/translatable/{field_name}'
+  pattern: 'admin/config/regional/content_translation/translatable/{entity_type}/{field_name}'
   defaults:
     _form: 'Drupal\content_translation\Form\TranslatableForm'
   requirements:
diff --git a/core/modules/content_translation/lib/Drupal/content_translation/ContentTranslationController.php b/core/modules/content_translation/lib/Drupal/content_translation/ContentTranslationController.php
index 6948642..ac8b7a4 100644
--- a/core/modules/content_translation/lib/Drupal/content_translation/ContentTranslationController.php
+++ b/core/modules/content_translation/lib/Drupal/content_translation/ContentTranslationController.php
@@ -51,7 +51,7 @@ public function removeTranslation(EntityInterface $entity, $langcode) {
     // Remove field translations.
     foreach (field_info_instances($entity->entityType(), $entity->bundle()) as $instance) {
       $field_name = $instance['field_name'];
-      $field = field_info_field($field_name);
+      $field = $instance->getField();
       if ($field['translatable']) {
         $entity->{$field_name}[$langcode] = array();
       }
diff --git a/core/modules/content_translation/lib/Drupal/content_translation/Form/TranslatableForm.php b/core/modules/content_translation/lib/Drupal/content_translation/Form/TranslatableForm.php
index bdeb983..8ffa451 100644
--- a/core/modules/content_translation/lib/Drupal/content_translation/Form/TranslatableForm.php
+++ b/core/modules/content_translation/lib/Drupal/content_translation/Form/TranslatableForm.php
@@ -8,7 +8,8 @@
 namespace Drupal\content_translation\Form;
 
 use Drupal\Core\Form\ConfirmFormBase;
-use Drupal\field\Field;
+use Drupal\field\Plugin\Core\Entity\Field;
+use Drupal\field\field as FieldInfo;
 
 /**
  * Provides a confirm form for changing translatable status on translation
@@ -19,9 +20,9 @@ class TranslatableForm extends ConfirmFormBase {
   /**
    * The field info we are changing translatable status on.
    *
-   * @var array.
+   * @var \Drupal\field\Plugin\Core\Entity\Field
    */
-  protected $fieldInfo;
+  protected $field;
 
   /**
    * The field name we are changing translatable
@@ -42,7 +43,7 @@ public function getFormID() {
    * {@inheritdoc}
    */
   public function getQuestion() {
-    if ($field['translatable']) {
+    if ($this->field['translatable']) {
       $question = t('Are you sure you want to disable translation for the %name field?', array('%name' => $this->fieldName));
     }
     else {
@@ -58,7 +59,7 @@ public function getDescription() {
     $description = t('By submitting this form these changes will apply to the %name field everywhere it is used.',
       array('%name' => $this->fieldName)
     );
-    $description .= $this->fieldInfo['translatable'] ? "<br>" . t("<strong>All the existing translations of this field will be deleted.</strong><br>This action cannot be undone.") : '';
+    $description .= $this->field['translatable'] ? "<br>" . t("<strong>All the existing translations of this field will be deleted.</strong><br>This action cannot be undone.") : '';
     return $description;
   }
 
@@ -74,9 +75,9 @@ public function getCancelPath() {
    * @param string $field_name
    *   The field name.
    */
-  public function buildForm(array $form, array &$form_state, $field_name = NULL) {
+  public function buildForm(array $form, array &$form_state, $entity_type = NULL, $field_name = NULL) {
     $this->fieldName = $field_name;
-    $this->fieldInfo = Field::fieldInfo($field_name);
+    $this->fieldInfo = FieldInfo::fieldInfo()->getField($entity_type, $field_name);
 
     return parent::buildForm($form, $form_state);
   }
@@ -127,6 +128,7 @@ public function submitForm(array &$form, array &$form_state) {
       array(
         'content_translation_translatable_switch', array(
           !$translatable,
+          $this->field['entity_type'],
           $this->fieldName,
         ),
       ),
diff --git a/core/modules/content_translation/lib/Drupal/content_translation/Tests/ContentTranslationSettingsTest.php b/core/modules/content_translation/lib/Drupal/content_translation/Tests/ContentTranslationSettingsTest.php
index 80c5a45..4720988 100644
--- a/core/modules/content_translation/lib/Drupal/content_translation/Tests/ContentTranslationSettingsTest.php
+++ b/core/modules/content_translation/lib/Drupal/content_translation/Tests/ContentTranslationSettingsTest.php
@@ -89,7 +89,7 @@ function testSettingsUI() {
     );
     $this->assertSettings('comment', 'comment_node_article', TRUE, $edit);
     field_info_cache_clear();
-    $field = field_info_field('comment_body');
+    $field = field_info_field('comment', 'comment_body');
     $this->assertTrue($field['translatable'], 'Comment body is translatable.');
 
     // Test that language settings are correctly stored.
diff --git a/core/modules/content_translation/lib/Drupal/content_translation/Tests/ContentTranslationSyncImageTest.php b/core/modules/content_translation/lib/Drupal/content_translation/Tests/ContentTranslationSyncImageTest.php
index 54d234e..c813790 100644
--- a/core/modules/content_translation/lib/Drupal/content_translation/Tests/ContentTranslationSyncImageTest.php
+++ b/core/modules/content_translation/lib/Drupal/content_translation/Tests/ContentTranslationSyncImageTest.php
@@ -57,7 +57,8 @@ protected function setupTestFields() {
     $this->cardinality = 3;
 
     entity_create('field_entity', array(
-      'field_name' => $this->fieldName,
+      'name' => $this->fieldName,
+      'entity_type' => $this->entityType,
       'type' => 'image',
       'cardinality' => $this->cardinality,
       'translatable' => TRUE,
diff --git a/core/modules/content_translation/lib/Drupal/content_translation/Tests/ContentTranslationTestBase.php b/core/modules/content_translation/lib/Drupal/content_translation/Tests/ContentTranslationTestBase.php
index b635c45..0ea5ae6 100644
--- a/core/modules/content_translation/lib/Drupal/content_translation/Tests/ContentTranslationTestBase.php
+++ b/core/modules/content_translation/lib/Drupal/content_translation/Tests/ContentTranslationTestBase.php
@@ -162,8 +162,9 @@ protected function setupTestFields() {
     $this->fieldName = 'field_test_et_ui_test';
 
     entity_create('field_entity', array(
-      'field_name' => $this->fieldName,
+      'name' => $this->fieldName,
       'type' => 'text',
+      'entity_type' => $this->entityType,
       'cardinality' => 1,
       'translatable' => TRUE,
     ))->save();
diff --git a/core/modules/datetime/lib/Drupal/datetime/Tests/DatetimeFieldTest.php b/core/modules/datetime/lib/Drupal/datetime/Tests/DatetimeFieldTest.php
index af66e0d..14bbf1f 100644
--- a/core/modules/datetime/lib/Drupal/datetime/Tests/DatetimeFieldTest.php
+++ b/core/modules/datetime/lib/Drupal/datetime/Tests/DatetimeFieldTest.php
@@ -57,13 +57,14 @@ function setUp() {
 
     // Create a field with settings to validate.
     $this->field = entity_create('field_entity', array(
-      'field_name' => drupal_strtolower($this->randomName()),
+      'name' => drupal_strtolower($this->randomName()),
+      'entity_type' => 'entity_test',
       'type' => 'datetime',
       'settings' => array('datetime_type' => 'date'),
     ));
     $this->field->save();
     $this->instance = entity_create('field_instance', array(
-      'field_name' => $this->field->id(),
+      'name' => $this->field->id(),
       'entity_type' => 'entity_test',
       'bundle' => 'entity_test',
       'settings' => array(
diff --git a/core/modules/edit/lib/Drupal/edit/Access/EditEntityFieldAccessCheck.php b/core/modules/edit/lib/Drupal/edit/Access/EditEntityFieldAccessCheck.php
index 9ec569a..6c940d8 100644
--- a/core/modules/edit/lib/Drupal/edit/Access/EditEntityFieldAccessCheck.php
+++ b/core/modules/edit/lib/Drupal/edit/Access/EditEntityFieldAccessCheck.php
@@ -41,7 +41,8 @@ public function access(Route $route, Request $request) {
    * Implements EntityFieldAccessCheckInterface::accessEditEntityField().
    */
   public function accessEditEntityField(EntityInterface $entity, $field_name) {
-    return $entity->access('update') && ($field = field_info_field($field_name)) && field_access('edit', $field, $entity->entityType(), $entity);
+    $entity_type = $entity->entityType();
+    return $entity->access('update') && ($field = field_info_field($entity_type, $field_name)) && field_access('edit', $field, $entity_type, $entity);
   }
 
   /**
diff --git a/core/modules/edit/lib/Drupal/edit/Tests/EditTestBase.php b/core/modules/edit/lib/Drupal/edit/Tests/EditTestBase.php
index 649f033..a7d38af 100644
--- a/core/modules/edit/lib/Drupal/edit/Tests/EditTestBase.php
+++ b/core/modules/edit/lib/Drupal/edit/Tests/EditTestBase.php
@@ -19,7 +19,7 @@ class EditTestBase extends DrupalUnitTestBase {
    *
    * @var array
    */
-  public static $modules = array('system', 'entity', 'entity_test', 'field', 'field_sql_storage', 'field_test', 'number', 'text', 'edit');
+  public static $modules = array('system', 'entity', 'entity_test', 'field', 'field_test', 'number', 'text', 'edit');
   /**
    * Sets the default field storage backend for fields created during tests.
    */
@@ -55,7 +55,8 @@ function setUp() {
   function createFieldWithInstance($field_name, $type, $cardinality, $label, $instance_settings, $widget_type, $widget_settings, $formatter_type, $formatter_settings) {
     $field = $field_name . '_field';
     $this->$field = entity_create('field_entity', array(
-      'field_name' => $field_name,
+      'name' => $field_name,
+      'entity_type' => 'entity_test',
       'type' => $type,
       'cardinality' => $cardinality,
     ));
diff --git a/core/modules/email/lib/Drupal/email/Tests/EmailFieldTest.php b/core/modules/email/lib/Drupal/email/Tests/EmailFieldTest.php
index 2d76d76..25e599b 100644
--- a/core/modules/email/lib/Drupal/email/Tests/EmailFieldTest.php
+++ b/core/modules/email/lib/Drupal/email/Tests/EmailFieldTest.php
@@ -62,7 +62,8 @@ function testEmailField() {
     // Create a field with settings to validate.
     $field_name = drupal_strtolower($this->randomName());
     $this->field = entity_create('field_entity', array(
-      'field_name' => $field_name,
+      'name' => $field_name,
+      'entity_type' => 'entity_test',
       'type' => 'email',
     ));
     $this->field->save();
diff --git a/core/modules/email/lib/Drupal/email/Tests/EmailItemTest.php b/core/modules/email/lib/Drupal/email/Tests/EmailItemTest.php
index 7e72163..b4a1bfe 100644
--- a/core/modules/email/lib/Drupal/email/Tests/EmailItemTest.php
+++ b/core/modules/email/lib/Drupal/email/Tests/EmailItemTest.php
@@ -36,7 +36,8 @@ public function setUp() {
 
     // Create an email field and instance for validation.
     entity_create('field_entity', array(
-      'field_name' => 'field_email',
+      'name' => 'field_email',
+      'entity_type' => 'entity_test',
       'type' => 'email',
     ))->save();
     entity_create('field_instance', array(
diff --git a/core/modules/entity/lib/Drupal/entity/EntityDisplayBase.php b/core/modules/entity/lib/Drupal/entity/EntityDisplayBase.php
index 99008e2..d9dfa8e 100644
--- a/core/modules/entity/lib/Drupal/entity/EntityDisplayBase.php
+++ b/core/modules/entity/lib/Drupal/entity/EntityDisplayBase.php
@@ -220,7 +220,7 @@ public function setComponent($name, array $options = array()) {
     }
 
     if ($instance = field_info_instance($this->targetEntityType, $name, $this->bundle)) {
-      $field = field_info_field($instance['field_name']);
+      $field = $instance->getField();
       $options = $this->pluginManager->prepareConfiguration($field['type'], $options);
 
       // Clear the persisted plugin, if any.
diff --git a/core/modules/entity/lib/Drupal/entity/Tests/EntityDisplayTest.php b/core/modules/entity/lib/Drupal/entity/Tests/EntityDisplayTest.php
index 6a0ddc5..b0f133f 100644
--- a/core/modules/entity/lib/Drupal/entity/Tests/EntityDisplayTest.php
+++ b/core/modules/entity/lib/Drupal/entity/Tests/EntityDisplayTest.php
@@ -131,7 +131,7 @@ public function testExtraFieldComponent() {
    * Tests the behavior of a field component within an EntityDisplay object.
    */
   public function testFieldComponent() {
-    $this->enableModules(array('field_sql_storage', 'field_test'));
+    $this->enableModules(array('field_test'));
 
     $display = entity_create('entity_display', array(
       'targetEntityType' => 'entity_test',
@@ -142,7 +142,8 @@ public function testFieldComponent() {
     $field_name = 'test_field';
     // Create a field and an instance.
     $field = entity_create('field_entity', array(
-      'field_name' => $field_name,
+      'name' => $field_name,
+      'entity_type' => 'entity_test',
       'type' => 'test_field'
     ));
     $field->save();
@@ -202,7 +203,7 @@ public function testFieldComponent() {
    * Tests renaming and deleting a bundle.
    */
   public function testRenameDeleteBundle() {
-    $this->enableModules(array('field_sql_storage', 'field_test', 'node', 'system', 'text'));
+    $this->enableModules(array('field_test', 'node', 'system', 'text'));
     $this->installSchema('system', array('variable'));
     $this->installSchema('node', array('node'));
 
@@ -239,12 +240,13 @@ public function testRenameDeleteBundle() {
    * Tests deleting field instance.
    */
   public function testDeleteFieldInstance() {
-    $this->enableModules(array('field_sql_storage', 'field_test'));
+    $this->enableModules(array('field_test'));
 
     $field_name = 'test_field';
     // Create a field and an instance.
     $field = entity_create('field_entity', array(
-      'field_name' => $field_name,
+      'name' => $field_name,
+      'entity_type' => 'entity_test',
       'type' => 'test_field'
     ));
     $field->save();
diff --git a/core/modules/entity/lib/Drupal/entity/Tests/EntityFormDisplayTest.php b/core/modules/entity/lib/Drupal/entity/Tests/EntityFormDisplayTest.php
index a74c966..f96a652 100644
--- a/core/modules/entity/lib/Drupal/entity/Tests/EntityFormDisplayTest.php
+++ b/core/modules/entity/lib/Drupal/entity/Tests/EntityFormDisplayTest.php
@@ -53,7 +53,7 @@ public function testEntityGetFromDisplay() {
    * Tests the behavior of a field component within an EntityFormDisplay object.
    */
   public function testFieldComponent() {
-    $this->enableModules(array('field_sql_storage', 'field_test'));
+    $this->enableModules(array('field_test'));
 
     $form_display = entity_create('entity_form_display', array(
       'targetEntityType' => 'entity_test',
@@ -64,7 +64,8 @@ public function testFieldComponent() {
     // Create a field and an instance.
     $field_name = 'test_field';
     $field = entity_create('field_entity', array(
-      'field_name' => $field_name,
+      'name' => $field_name,
+      'entity_type' => 'entity_test',
       'type' => 'test_field'
     ));
     $field->save();
diff --git a/core/modules/entity_reference/entity_reference.module b/core/modules/entity_reference/entity_reference.module
index 54a7bac..718bfa8 100644
--- a/core/modules/entity_reference/entity_reference.module
+++ b/core/modules/entity_reference/entity_reference.module
@@ -50,7 +50,7 @@ function entity_reference_field_info() {
 function entity_reference_entity_field_info_alter(&$info, $entity_type) {
   foreach (field_info_instances($entity_type) as $bundle_name => $instances) {
     foreach ($instances as $field_name => $instance) {
-      $field = field_info_field($field_name);
+      $field = $instance->getField();
       if ($field['type'] != 'entity_reference') {
         continue;
       }
@@ -178,7 +178,7 @@ function entity_reference_field_entity_update(FieldInterface $field) {
     return;
   }
 
-  $field_name = $field->id();
+  $field_name = $field->getFieldName();
 
   foreach ($field->bundles() as $entity_type => $bundles) {
     foreach ($bundles as $bundle) {
@@ -407,14 +407,14 @@ function entity_reference_create_instance($entity_type, $bundle, $field_name, $f
   }
 
   // Look for or add the specified field to the requested entity bundle.
-  $field = field_info_field($field_name);
+  $field = field_info_field($entity_type, $field_name);
   $instance = field_info_instance($entity_type, $field_name, $bundle);
 
   if (empty($field)) {
     $field = array(
-      'field_name' => $field_name,
+      'name' => $field_name,
       'type' => 'entity_reference',
-      'entity_types' => array($entity_type),
+      'entity_type' => $entity_type,
       'settings' => array(
         'target_type' => $target_entity_type,
       ),
@@ -425,7 +425,6 @@ function entity_reference_create_instance($entity_type, $bundle, $field_name, $f
   if (empty($instance)) {
     $instance = array(
       'field_name' => $field_name,
-      'entity_type' => $entity_type,
       'bundle' => $bundle,
       'label' => $field_label,
       'settings' => array(
diff --git a/core/modules/entity_reference/lib/Drupal/entity_reference/EntityReferenceController.php b/core/modules/entity_reference/lib/Drupal/entity_reference/EntityReferenceController.php
index b6099f1..644304a 100644
--- a/core/modules/entity_reference/lib/Drupal/entity_reference/EntityReferenceController.php
+++ b/core/modules/entity_reference/lib/Drupal/entity_reference/EntityReferenceController.php
@@ -69,7 +69,7 @@ public static function create(ContainerInterface $container) {
    *   The matched labels as json.
    */
   public function handleAutocomplete(Request $request, $type, $field_name, $entity_type, $bundle_name, $entity_id) {
-    if (!$field = field_info_field($field_name)) {
+    if (!$field = field_info_field($entity_type, $field_name)) {
       throw new AccessDeniedHttpException();
     }
 
diff --git a/core/modules/entity_reference/lib/Drupal/entity_reference/Plugin/entity_reference/selection/SelectionBase.php b/core/modules/entity_reference/lib/Drupal/entity_reference/Plugin/entity_reference/selection/SelectionBase.php
index de4729c..ab8886d 100644
--- a/core/modules/entity_reference/lib/Drupal/entity_reference/Plugin/entity_reference/selection/SelectionBase.php
+++ b/core/modules/entity_reference/lib/Drupal/entity_reference/Plugin/entity_reference/selection/SelectionBase.php
@@ -108,7 +108,7 @@ public static function settingsForm(&$field, &$instance) {
     $fields = drupal_map_assoc(drupal_schema_fields_sql($entity_info['base_table']));
     foreach (field_info_instances($field['settings']['target_type']) as $bundle_instances) {
       foreach ($bundle_instances as $instance_name => $instance_info) {
-        $field_info = field_info_field($instance_name);
+        $field_info = $instance_info->getField();
         foreach ($field_info['columns'] as $column_name => $column_info) {
           $fields[$instance_name . '.' . $column_name] = t('@label (@column)', array('@label' => $instance_info['label'], '@column' => $column_name));
         }
diff --git a/core/modules/entity_reference/lib/Drupal/entity_reference/Tests/EntityReferenceAutoCreateTest.php b/core/modules/entity_reference/lib/Drupal/entity_reference/Tests/EntityReferenceAutoCreateTest.php
index f5f74d0..6cccb4d 100644
--- a/core/modules/entity_reference/lib/Drupal/entity_reference/Tests/EntityReferenceAutoCreateTest.php
+++ b/core/modules/entity_reference/lib/Drupal/entity_reference/Tests/EntityReferenceAutoCreateTest.php
@@ -36,12 +36,13 @@ function setUp() {
     $this->referenced_type = $referenced->type;
 
     entity_create('field_entity', array(
+      'name' => 'test_field',
+      'entity_type' => 'node',
       'translatable' => FALSE,
       'entity_types' => array(),
       'settings' => array(
         'target_type' => 'node',
       ),
-      'field_name' => 'test_field',
       'type' => 'entity_reference',
       'cardinality' => FIELD_CARDINALITY_UNLIMITED,
     ))->save();
diff --git a/core/modules/entity_reference/lib/Drupal/entity_reference/Tests/EntityReferenceItemTest.php b/core/modules/entity_reference/lib/Drupal/entity_reference/Tests/EntityReferenceItemTest.php
index 8c17fd6..2a50949 100644
--- a/core/modules/entity_reference/lib/Drupal/entity_reference/Tests/EntityReferenceItemTest.php
+++ b/core/modules/entity_reference/lib/Drupal/entity_reference/Tests/EntityReferenceItemTest.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\entity_reference\Tests;
 
+use Drupal\Core\Entity\DatabaseStorageController;
 use Drupal\Core\Entity\Field\FieldInterface;
 use Drupal\Core\Entity\Field\FieldItemInterface;
 use Drupal\Core\Language\Language;
@@ -110,16 +111,16 @@ public function testEntityReferenceItem() {
    * Tests foreign key support.
    */
   public function testEntityReferenceFieldSchema() {
-    $field = field_info_field('field_test_taxonomy');
+    $field = field_info_field('entity_test', 'field_test_taxonomy');
     $foreign_key_column_name = 'target_id';
 
     // Grab the SQL schema and verify that the 'foreign keys' are present.
-    $schemas = _field_sql_storage_schema($field);
-    $schema = $schemas[_field_sql_storage_tablename($field)];
+    $schemas = DatabaseStorageController::_fieldSqlSchema($field);
+    $schema = $schemas[DatabaseStorageController::_fieldTableName($field)];
     $this->assertEqual(count($schema['foreign keys']), 1, 'There is 1 foreign key in the schema.');
 
     $foreign_key = reset($schema['foreign keys']);
-    $foreign_key_column = _field_sql_storage_columnname($field['field_name'], $foreign_key_column_name);
+    $foreign_key_column = DatabaseStorageController::_fieldColumnName($field, $foreign_key_column_name);
     $this->assertEqual($foreign_key['table'], 'taxonomy_term_data', 'Foreign key table name preserved in the schema.');
     $this->assertEqual($foreign_key['columns'][$foreign_key_column], 'tid', 'Foreign key column name preserved in the schema.');
 
@@ -127,10 +128,10 @@ public function testEntityReferenceFieldSchema() {
     // foreign key is present.
     $field_name = 'field_test_vocabulary';
     entity_reference_create_instance('entity_test', 'entity_test', $field_name, 'Test vocabulary reference', 'taxonomy_vocabulary');
-    $field = field_info_field($field_name);
+    $field = field_info_field('entity_test', $field_name);
 
-    $schemas = _field_sql_storage_schema($field);
-    $schema = $schemas[_field_sql_storage_tablename($field)];
+    $schemas = DatabaseStorageController::_fieldSqlSchema($field);
+    $schema = $schemas[DatabaseStorageController::_fieldTableName($field)];
     $this->assertFalse(isset($schema['foreign keys']), 'There is no foreign key in the schema.');
   }
 }
diff --git a/core/modules/entity_reference/lib/Drupal/entity_reference/Tests/EntityReferenceSelectionAccessTest.php b/core/modules/entity_reference/lib/Drupal/entity_reference/Tests/EntityReferenceSelectionAccessTest.php
index f064b77..8a3e60b 100644
--- a/core/modules/entity_reference/lib/Drupal/entity_reference/Tests/EntityReferenceSelectionAccessTest.php
+++ b/core/modules/entity_reference/lib/Drupal/entity_reference/Tests/EntityReferenceSelectionAccessTest.php
@@ -24,7 +24,7 @@ public static function getInfo() {
     );
   }
 
-  public static $modules = array('node', 'comment', 'entity_reference');
+  public static $modules = array('node', 'comment', 'entity_reference', 'entity_test');
 
   function setUp() {
     parent::setUp();
@@ -61,19 +61,20 @@ protected function assertReferenceable(FieldDefinitionInterface $field_definitio
   public function testNodeHandler() {
     // Create a field and instance.
     $field = entity_create('field_entity', array(
+      'name' => 'test_field',
+      'entity_type' => 'entity_test',
       'translatable' => FALSE,
       'entity_types' => array(),
       'settings' => array(
         'target_type' => 'node',
       ),
-      'field_name' => 'test_field',
       'type' => 'entity_reference',
       'cardinality' => '1',
     ));
     $field->save();
     $instance = entity_create('field_instance', array(
       'field_name' => 'test_field',
-      'entity_type' => 'test_entity',
+      'entity_type' => 'entity_test',
       'bundle' => 'test_bundle',
       'settings' => array(
         'handler' => 'default',
@@ -204,19 +205,19 @@ public function testNodeHandler() {
   public function testUserHandler() {
     // Create a field and instance.
     $field = entity_create('field_entity', array(
+      'name' => 'test_field',
+      'entity_type' => 'entity_test',
       'translatable' => FALSE,
-      'entity_types' => array(),
       'settings' => array(
         'target_type' => 'user',
       ),
-      'field_name' => 'test_field',
       'type' => 'entity_reference',
       'cardinality' => '1',
     ));
     $field->save();
     $instance = entity_create('field_instance', array(
       'field_name' => 'test_field',
-      'entity_type' => 'test_entity',
+      'entity_type' => 'entity_test',
       'bundle' => 'test_bundle',
       'settings' => array(
         'handler' => 'default',
@@ -349,19 +350,20 @@ public function testUserHandler() {
   public function testCommentHandler() {
     // Create a field and instance.
     $field = entity_create('field_entity', array(
+      'name' => 'test_field',
+      'entity_type' => 'entity_test',
       'translatable' => FALSE,
       'entity_types' => array(),
       'settings' => array(
         'target_type' => 'comment',
       ),
-      'field_name' => 'test_field',
       'type' => 'entity_reference',
       'cardinality' => '1',
     ));
     $field->save();
     $instance = entity_create('field_instance', array(
       'field_name' => 'test_field',
-      'entity_type' => 'test_entity',
+      'entity_type' => 'entity_test',
       'bundle' => 'test_bundle',
       'settings' => array(
         'handler' => 'default',
diff --git a/core/modules/entity_reference/lib/Drupal/entity_reference/Tests/EntityReferenceSelectionSortTest.php b/core/modules/entity_reference/lib/Drupal/entity_reference/Tests/EntityReferenceSelectionSortTest.php
index f7b8fbc..230e4dc 100644
--- a/core/modules/entity_reference/lib/Drupal/entity_reference/Tests/EntityReferenceSelectionSortTest.php
+++ b/core/modules/entity_reference/lib/Drupal/entity_reference/Tests/EntityReferenceSelectionSortTest.php
@@ -22,7 +22,7 @@ public static function getInfo() {
     );
   }
 
-  public static $modules = array('node', 'entity_reference');
+  public static $modules = array('node', 'entity_reference', 'entity_test');
 
   function setUp() {
     parent::setUp();
@@ -37,7 +37,8 @@ function setUp() {
   public function testSort() {
     // Add text field to entity, to sort by.
     entity_create('field_entity', array(
-      'field_name' => 'field_text',
+      'name' => 'field_text',
+      'entity_type' => 'node',
       'type' => 'text',
       'entity_types' => array('node'),
     ))->save();
@@ -54,19 +55,19 @@ public function testSort() {
 
     // Create a field and instance.
     $field = entity_create('field_entity', array(
+      'name' => 'test_field',
+      'entity_type' => 'entity_test',
       'translatable' => FALSE,
-      'entity_types' => array(),
       'settings' => array(
         'target_type' => 'node',
       ),
-      'field_name' => 'test_field',
       'type' => 'entity_reference',
       'cardinality' => 1,
     ));
     $field->save();
     $instance = entity_create('field_instance', array(
       'field_name' => 'test_field',
-      'entity_type' => 'test_entity',
+      'entity_type' => 'entity_test',
       'bundle' => 'test_bundle',
       'settings' => array(
         'handler' => 'default',
diff --git a/core/modules/entity_reference/lib/Drupal/entity_reference/Tests/Views/SelectionTest.php b/core/modules/entity_reference/lib/Drupal/entity_reference/Tests/Views/SelectionTest.php
index 8127682..e5d58f4 100644
--- a/core/modules/entity_reference/lib/Drupal/entity_reference/Tests/Views/SelectionTest.php
+++ b/core/modules/entity_reference/lib/Drupal/entity_reference/Tests/Views/SelectionTest.php
@@ -14,7 +14,7 @@
  */
 class SelectionTest extends WebTestBase {
 
-  public static $modules = array('views', 'entity_reference', 'entity_reference_test');
+  public static $modules = array('views', 'entity_reference', 'entity_reference_test', 'entity_test');
 
   public static function getInfo() {
     return array(
@@ -41,19 +41,19 @@ public function testSelectionHandler() {
 
     // Create a field and instance.
     $field = entity_create('field_entity', array(
+      'name' => 'test_field',
+      'entity_type' => 'entity_test',
       'translatable' => FALSE,
-      'entity_types' => array(),
       'settings' => array(
         'target_type' => 'node',
       ),
-      'field_name' => 'test_field',
       'type' => 'entity_reference',
       'cardinality' => '1',
     ));
     $field->save();
     $instance = entity_create('field_instance', array(
       'field_name' => 'test_field',
-      'entity_type' => 'test_entity',
+      'entity_type' => 'entity_test',
       'bundle' => 'test_bundle',
       'settings' => array(
         'handler' => 'views',
diff --git a/core/modules/field/config/schema/field.schema.yml b/core/modules/field/config/schema/field.schema.yml
index 1b23198..d911f27 100644
--- a/core/modules/field/config/schema/field.schema.yml
+++ b/core/modules/field/config/schema/field.schema.yml
@@ -30,6 +30,9 @@ field.field.*:
     langcode:
       type: string
       label: 'Default language'
+    entity_type:
+      type: string
+      label: 'Entity type'
     type:
       type: string
       label: 'Type'
@@ -41,28 +44,6 @@ field.field.*:
     active:
       type: boolean
       label: 'Active'
-    entity_types:
-      type: sequence
-      label: 'Allowed entity types'
-      sequence:
-        - type: string
-          label: 'Entity type'
-    storage:
-      type: mapping
-      label: 'Storage'
-      mapping:
-        type:
-          type: string
-          label: 'Type'
-        settings:
-          type: field_storage.[%parent.type].settings
-          label: 'Settings'
-        module:
-          type: string
-          label: 'Module'
-        active:
-          type: boolean
-          label: 'Active'
     locked:
       type: boolean
       label: 'Locked'
@@ -101,9 +82,6 @@ field.instance.*.*.*:
     field_uuid:
       type: string
       label: 'Field UUID'
-    entity_type:
-      type: string
-      label: 'Allowed entity types'
     bundle:
       type: string
       label: 'Bundle'
diff --git a/core/modules/field/field.api.php b/core/modules/field/field.api.php
index 02fd704..72df2f0 100644
--- a/core/modules/field/field.api.php
+++ b/core/modules/field/field.api.php
@@ -810,7 +810,7 @@ function hook_field_storage_write(\Drupal\Core\Entity\EntityInterface $entity, $
 function hook_field_storage_delete(\Drupal\Core\Entity\EntityInterface $entity, $fields) {
   foreach (field_info_instances($entity->entityType(), $entity->bundle()) as $instance) {
     if (isset($fields[$instance['field_id']])) {
-      $field = field_info_field_by_id($instance['field_id']);
+      $field = $instance->getField();
       field_sql_storage_field_storage_purge($entity, $field, $instance);
     }
   }
@@ -1050,7 +1050,7 @@ function hook_field_storage_delete_field($field) {
  *   The instance being deleted.
  */
 function hook_field_storage_delete_instance($instance) {
-  $field = field_info_field($instance['field_name']);
+  $field = $instance->getField();
   $table_name = _field_sql_storage_tablename($field);
   $revision_name = _field_sql_storage_revision_tablename($field);
   db_update($table_name)
diff --git a/core/modules/field/field.attach.inc b/core/modules/field/field.attach.inc
index 5ed17ff..33a3736 100644
--- a/core/modules/field/field.attach.inc
+++ b/core/modules/field/field.attach.inc
@@ -12,45 +12,6 @@
 use Drupal\Core\Language\Language;
 
 /**
- * @defgroup field_storage Field Storage API
- * @{
- * Implements a storage engine for Field API data.
- *
- * The Field Attach API uses the Field Storage API to perform all "database
- * access". Each Field Storage API hook function defines a primitive database
- * operation such as read, write, or delete. The default field storage module,
- * field_sql_storage.module, uses the local SQL database to implement these
- * operations, but alternative field storage backends can choose to represent
- * the data in SQL differently or use a completely different storage mechanism
- * such as a cloud-based database.
- *
- * Each field defines which storage backend it uses. The Drupal configuration
- * 'field.settings.default_storage' identifies the storage backend used by
- * default.
- *
- * See @link field Field API @endlink for information about the other parts of
- * the Field API.
- */
-
-/**
- * Argument for an update operation.
- *
- * This is used in hook_field_storage_write when updating an existing entity.
- */
-const FIELD_STORAGE_UPDATE = 'update';
-
-/**
- * Argument for an insert operation.
- *
- * This is used in hook_field_storage_write when inserting a new entity.
- */
-const FIELD_STORAGE_INSERT = 'insert';
-
-/**
- * @} End of "defgroup field_storage".
- */
-
-/**
  * @defgroup field_attach Field Attach API
  * @{
  * Operates on Field API data attached to Drupal entities.
@@ -169,7 +130,7 @@ function field_invoke_method($method, $target_function, EntityInterface $entity,
     $target = call_user_func($target_function, $instance);
 
     if (method_exists($target, $method)) {
-      $field = field_info_field_by_id($instance['field_id']);
+      $field = $instance->getField();
       $field_name = $field['field_name'];
 
       // Determine the list of languages to iterate on.
@@ -281,7 +242,7 @@ function field_invoke_method_multiple($method, $target_function, array $entities
 
         // Unless a language code suggestion is provided we iterate on all the
         // available language codes.
-        $field = field_info_field_by_id($instance['field_id']);
+        $field = $instance->getField();
         $available_langcodes = field_available_languages($entity_type, $field);
         $langcode = !empty($options['langcode'][$id]) ? $options['langcode'][$id] : $options['langcode'];
         $langcodes = _field_language_suggestion($available_langcodes, $langcode, $field_name);
@@ -538,213 +499,6 @@ function field_attach_form(EntityInterface $entity, &$form, &$form_state, $langc
 }
 
 /**
- * Loads fields for the current revisions of a group of entities.
- *
- * Loads all fields for each entity object in a group of a single entity type.
- * The loaded field values are added directly to the entity objects.
- *
- * field_attach_load() is automatically called by the default entity controller
- * class, and thus, in most cases, doesn't need to be explicitly called by the
- * entity type module.
- *
- * @param $entity_type
- *   The type of entities in $entities; e.g., 'node' or 'user'.
- * @param $entities
- *   An array of entities for which to load fields, keyed by entity ID. Each
- *   entity needs to have its 'bundle', 'id' and (if applicable) 'revision' keys
- *   filled in. The function adds the loaded field data directly in the entity
- *   objects of the $entities array.
- * @param $age
- *   FIELD_LOAD_CURRENT to load the most recent revision for all fields, or
- *   FIELD_LOAD_REVISION to load the version indicated by each entity. Defaults
- *   to FIELD_LOAD_CURRENT; use field_attach_load_revision() instead of passing
- *   FIELD_LOAD_REVISION.
- * @param $options
- *   An associative array of additional options, with the following keys:
- *   - instance: A field instance entity, If provided, only values for the
- *     corresponding field will be loaded, and no cache is written. This
- *     option is only supported when all $entities are within the same bundle.
- *
- * @deprecated as of Drupal 8.0. Use the entity system instead.
- */
-function field_attach_load($entity_type, $entities, $age = FIELD_LOAD_CURRENT, $options = array()) {
-  $load_current = $age == FIELD_LOAD_CURRENT;
-  $load_deleted = !empty($options['instance']->deleted);
-
-  // Merge default options.
-  $options += array('instance' => NULL);
-  // Set options for hook invocations.
-  $hook_options = array(
-    'deleted' => $load_deleted,
-  );
-  if ($options['instance']) {
-    $hook_options['field_id'] = $options['instance']->field_uuid;
-  }
-
-  $info = entity_get_info($entity_type);
-  // Only the most current revision of non-deleted fields for cacheable entity
-  // types can be cached.
-  $cache_read = $load_current && $info['field_cache'] && !$load_deleted;
-  // In addition, do not write to the cache when loading a single field.
-  $cache_write = $cache_read && !isset($options['instance']);
-
-  if (empty($entities)) {
-    return;
-  }
-
-  // Ensure we are working with a BC mode entity.
-  foreach ($entities as $id => $entity) {
-    $entities[$id] = $entity->getBCEntity();
-  }
-
-  // Assume all entities will need to be queried. Entities found in the cache
-  // will be removed from the list.
-  $queried_entities = $entities;
-
-  // Fetch available entities from cache, if applicable.
-  if ($cache_read) {
-    // Build the list of cache entries to retrieve.
-    $cids = array();
-    foreach ($entities as $id => $entity) {
-      $cids[] = "field:$entity_type:$id";
-    }
-    $cache = cache('field')->getMultiple($cids);
-    // Put the cached field values back into the entities and remove them from
-    // the list of entities to query.
-    foreach ($entities as $id => $entity) {
-      $cid = "field:$entity_type:$id";
-      if (isset($cache[$cid])) {
-        unset($queried_entities[$id]);
-        foreach ($cache[$cid]->data as $field_name => $values) {
-          $entity->$field_name = $values;
-        }
-      }
-    }
-  }
-
-  // Fetch other entities from their storage location.
-  if ($queried_entities) {
-    // The invoke order is:
-    // - hook_field_storage_pre_load()
-    // - storage backend's hook_field_storage_load()
-    // - Field class's prepareCache() method.
-    // - hook_field_attach_load()
-
-    // Invoke hook_field_storage_pre_load(): let any module load field
-    // data before the storage engine, accumulating along the way.
-    $skip_fields = array();
-    foreach (module_implements('field_storage_pre_load') as $module) {
-      $function = $module . '_field_storage_pre_load';
-      $function($entity_type, $queried_entities, $age, $skip_fields, $hook_options);
-    }
-
-    // Collect the storage backends used by the remaining fields in the entities.
-    $storages = array();
-    foreach ($queried_entities as $entity) {
-      $id = $entity->id();
-      $vid = $entity->getRevisionId();
-
-      // Determine the list of field instances to work on.
-      if ($options['instance']) {
-        $instances = array($options['instance']);
-      }
-      else {
-        $instances = field_info_instances($entity_type, $entity->bundle());
-      }
-
-      foreach ($instances as $instance) {
-        $field = $instance->getField();
-        $field_name = $field->id();
-        if (!isset($queried_entities[$id]->{$field_name})) {
-          $queried_entities[$id]->{$field_name} = array();
-        }
-        if (!isset($skip_fields[$field->uuid])) {
-          $storages[$field->storage['type']][$field->uuid][] = $load_current ? $id : $vid;
-        }
-      }
-    }
-
-    // Invoke hook_field_storage_load() on the relevant storage backends.
-    foreach ($storages as $storage => $fields) {
-      $storage_info = field_info_storage_types($storage);
-      module_invoke($storage_info['module'], 'field_storage_load', $entity_type, $queried_entities, $age, $fields, $hook_options);
-    }
-
-    // Invoke the field type's prepareCache() method.
-    if (empty($options['instance'])) {
-      foreach ($queried_entities as $entity) {
-        \Drupal::entityManager()
-          ->getStorageController($entity_type)
-          ->invokeFieldItemPrepareCache($entity);
-      }
-    }
-    else {
-      // Do not rely on invokeFieldItemPrepareCache(), which only works on
-      // fields listed in getFieldDefinitions(), and will fail if we are loading
-      // values for a deleted field. Instead, generate FieldItem objects
-      // directly, and call their prepareCache() method.
-      foreach ($queried_entities as $entity) {
-        $field = $options['instance']->getField();
-        $field_name = $field->id();
-        // Call the prepareCache() method on each item.
-        foreach ($entity->{$field_name} as $langcode => $values) {
-          $definition = _field_generate_entity_field_definition($field, $options['instance']);
-          $items = \Drupal::typedData()->create($definition, $values, $field_name, $entity);
-          foreach ($items as $item) {
-            $item->prepareCache();
-          }
-          $entity->{$field_name}[$langcode] = $items->getValue();
-        }
-      }
-    }
-
-    // Invoke hook_field_attach_load(): let other modules act on loading the
-    // entity.
-    module_invoke_all('field_attach_load', $entity_type, $queried_entities, $age, $options);
-
-    // Build cache data.
-    if ($cache_write) {
-      foreach ($queried_entities as $id => $entity) {
-        $data = array();
-        $instances = field_info_instances($entity_type, $entity->bundle());
-        foreach ($instances as $instance) {
-          $data[$instance['field_name']] = $queried_entities[$id]->{$instance['field_name']};
-        }
-        $cid = "field:$entity_type:$id";
-        cache('field')->set($cid, $data);
-      }
-    }
-  }
-}
-
-/**
- * Loads all fields for previous versions of a group of entities.
- *
- * Loading different versions of the same entities is not supported, and should
- * be done by separate calls to the function.
- *
- * field_attach_load_revision() is automatically called by the default entity
- * controller class, and thus, in most cases, doesn't need to be explicitly
- * called by the entity type module.
- *
- * @param $entity_type
- *   The type of entities in $entities; e.g. 'node' or 'user'.
- * @param $entities
- *   An array of entities for which to load fields, keyed by entity ID. Each
- *   entity needs to have its 'bundle', 'id' and (if applicable) 'revision' keys
- *   filled. The function adds the loaded field data directly in the entity
- *   objects of the $entities array.
- * @param $options
- *   An associative array of additional options. See field_attach_load() for
- *   details.
- *
- * @deprecated as of Drupal 8.0. Use the entity system instead.
- */
-function field_attach_load_revision($entity_type, $entities, $options = array()) {
-  return field_attach_load($entity_type, $entities, FIELD_LOAD_REVISION, $options);
-}
-
-/**
  * Performs field validation against form-submitted field values.
  *
  * There are two levels of validation for fields in forms: widget validation and
@@ -781,6 +535,7 @@ function field_attach_form_validate(EntityInterface $entity, $form, &$form_state
     return;
   }
 
+  $entity_type = $entity->entityType();
   $has_violations = FALSE;
   foreach ($entity as $field_name => $field) {
     $definition = $field->getDefinition();
@@ -790,7 +545,7 @@ function field_attach_form_validate(EntityInterface $entity, $form, &$form_state
         $has_violations = TRUE;
 
         // Place violations in $form_state.
-        $langcode = field_is_translatable($entity->entityType(), field_info_field($field_name)) ? $entity->language()->id : Language::LANGCODE_NOT_SPECIFIED;
+        $langcode = field_is_translatable($entity_type, field_info_field($entity_type, $field_name)) ? $entity->language()->id : Language::LANGCODE_NOT_SPECIFIED;
         $field_state = field_form_get_state($form['#parents'], $field_name, $langcode, $form_state);
         $field_state['constraint_violations'] = $field_violations;
         field_form_set_state($form['#parents'], $field_name, $langcode, $form_state, $field_state);
@@ -841,159 +596,6 @@ function field_attach_extract_form_values(EntityInterface $entity, $form, &$form
 }
 
 /**
- * Save field data for a new entity.
- *
- * The passed-in entity must already contain its id and (if applicable)
- * revision id attributes.
- * Default values (if any) will be saved for fields not present in the
- * $entity.
- *
- * @param \Drupal\Core\Entity\EntityInterface $entity
- *   The entity with fields to save.
- * @return
- *   Default values (if any) will be added to the $entity parameter for fields
- *   it leaves unspecified.
- *
- * @deprecated as of Drupal 8.0. Use the entity system instead.
- */
-function field_attach_insert(EntityInterface $entity) {
-  // Ensure we are working with a BC mode entity.
-  $entity = $entity->getBCEntity();
-
-  // Let any module insert field data before the storage engine, accumulating
-  // saved fields along the way.
-  $skip_fields = array();
-  foreach (module_implements('field_storage_pre_insert') as $module) {
-    $function = $module . '_field_storage_pre_insert';
-    $function($entity, $skip_fields);
-  }
-
-  // Collect the storage backends used by the remaining fields in the entities.
-  $storages = array();
-  foreach (field_info_instances($entity->entityType(), $entity->bundle()) as $instance) {
-    $field = field_info_field_by_id($instance['field_id']);
-    $field_id = $field['uuid'];
-    $field_name = $field['field_name'];
-    if (!empty($entity->$field_name)) {
-      // Collect the storage backend if the field has not been written yet.
-      if (!isset($skip_fields[$field_id])) {
-        $storages[$field['storage']['type']][$field_id] = $field_id;
-      }
-    }
-  }
-
-  // Field storage backends save any remaining unsaved fields.
-  foreach ($storages as $storage => $fields) {
-    $storage_info = field_info_storage_types($storage);
-    module_invoke($storage_info['module'], 'field_storage_write', $entity, FIELD_STORAGE_INSERT, $fields);
-  }
-}
-
-/**
- * Saves field data for an existing entity.
- *
- * @param \Drupal\Core\Entity\EntityInterface $entity
- *   The entity with fields to save.
- *
- * @deprecated as of Drupal 8.0. Use the entity system instead.
- */
-function field_attach_update(EntityInterface $entity) {
-  // Ensure we are working with a BC mode entity.
-  $entity = $entity->getBCEntity();
-
-  // Let any module update field data before the storage engine, accumulating
-  // saved fields along the way.
-  $skip_fields = array();
-  foreach (module_implements('field_storage_pre_update') as $module) {
-    $function = $module . '_field_storage_pre_update';
-    $function($entity, $skip_fields);
-  }
-
-  // Collect the storage backends used by the remaining fields in the entities.
-  $storages = array();
-  foreach (field_info_instances($entity->entityType(), $entity->bundle()) as $instance) {
-    $field = field_info_field_by_id($instance['field_id']);
-    $field_id = $field['uuid'];
-    // Collect the storage backend if the field has not been written yet.
-    if (!isset($skip_fields[$field_id])) {
-      $storages[$field['storage']['type']][$field_id] = $field_id;
-    }
-  }
-
-  // Field storage backends save any remaining unsaved fields.
-  foreach ($storages as $storage => $fields) {
-    $storage_info = field_info_storage_types($storage);
-    module_invoke($storage_info['module'], 'field_storage_write', $entity, FIELD_STORAGE_UPDATE, $fields);
-  }
-
-  $entity_info = $entity->entityInfo();
-  if ($entity_info['field_cache']) {
-    cache('field')->delete('field:' . $entity->entityType() . ':' . $entity->id());
-  }
-}
-
-/**
- * Deletes field data for an existing entity. This deletes all revisions of
- * field data for the entity.
- *
- * @param \Drupal\Core\Entity\EntityInterface $entity
- *   The entity whose field data to delete.
- *
- * @deprecated as of Drupal 8.0. Use the entity system instead.
- */
-function field_attach_delete(EntityInterface $entity) {
-  // Ensure we are working with a BC mode entity.
-  $entity = $entity->getBCEntity();
-
-  // Collect the storage backends used by the fields in the entities.
-  $storages = array();
-  foreach (field_info_instances($entity->entityType(), $entity->bundle()) as $instance) {
-    $field = field_info_field_by_id($instance['field_id']);
-    $field_id = $field['uuid'];
-    $storages[$field['storage']['type']][$field_id] = $field_id;
-  }
-
-  // Field storage backends delete their data.
-  foreach ($storages as $storage => $fields) {
-    $storage_info = field_info_storage_types($storage);
-    module_invoke($storage_info['module'], 'field_storage_delete', $entity, $fields);
-  }
-
-  $entity_info = $entity->entityInfo();
-  if ($entity_info['field_cache']) {
-    cache('field')->delete('field:' . $entity->entityType() . ':' . $entity->id());
-  }
-}
-
-/**
- * Delete field data for a single revision of an existing entity. The passed
- * entity must have a revision ID attribute.
- *
- * @param \Drupal\Core\Entity\EntityInterface $entity
- *   The entity with fields to save.
- *
- * @deprecated as of Drupal 8.0. Use the entity system instead.
- */
-function field_attach_delete_revision(EntityInterface $entity) {
-  // Ensure we are working with a BC mode entity.
-  $entity = $entity->getBCEntity();
-
-  // Collect the storage backends used by the fields in the entities.
-  $storages = array();
-  foreach (field_info_instances($entity->entityType(), $entity->bundle()) as $instance) {
-    $field = field_info_field_by_id($instance['field_id']);
-    $field_id = $field['uuid'];
-    $storages[$field['storage']['type']][$field_id] = $field_id;
-  }
-
-  // Field storage backends delete their data.
-  foreach ($storages as $storage => $fields) {
-    $storage_info = field_info_storage_types($storage);
-    module_invoke($storage_info['module'], 'field_storage_delete_revision', $entity, $fields);
-  }
-}
-
-/**
  * Prepares field data prior to display.
  *
  * This function lets field types and formatters load additional data needed for
diff --git a/core/modules/field/field.crud.inc b/core/modules/field/field.crud.inc
index ed129df..e9c1662 100644
--- a/core/modules/field/field.crud.inc
+++ b/core/modules/field/field.crud.inc
@@ -46,7 +46,7 @@
  *   entity_load('field_entity', 'field_name').
  */
 function field_read_field($field_name, $include_additional = array()) {
-  $fields = field_read_fields(array('field_name' => $field_name), $include_additional);
+  $fields = field_read_fields(array('name' => $field_name), $include_additional);
   return $fields ? current($fields) : FALSE;
 }
 
@@ -254,7 +254,7 @@ function field_purge_batch($batch_size) {
       'bundle' => $instance['bundle'],
     );
     // field_purge_data() will need the field array.
-    $field = field_info_field_by_id($instance['field_id']);
+    $field = $instance->getField();
     // Retrieve some entities.
     $query = $factory->get($entity_type)
       ->condition('id:' . $field['uuid'] . '.deleted', 1)
@@ -264,21 +264,12 @@ function field_purge_batch($batch_size) {
       $query->condition($info[$entity_type]['entity_keys']['bundle'], $ids->bundle);
     }
     $results = $query->execute();
-
     if ($results) {
-      $entities = array();
       foreach ($results as $revision_id => $entity_id) {
-        // This might not be the revision id if the entity type does not support
-        // revisions but _field_create_entity_from_ids() checks that and
-        // disregards this value so there is no harm setting it.
         $ids->revision_id = $revision_id;
         $ids->entity_id = $entity_id;
-        $entities[$entity_id] = _field_create_entity_from_ids($ids);
-      }
-      field_attach_load($entity_type, $entities, FIELD_LOAD_CURRENT, array('instance' => $instance));
-      foreach ($entities as $entity) {
-        // Purge the data for the entity.
-        field_purge_data($entity, $field, $instance);
+        $entity = _field_create_entity_from_ids($ids);
+        Drupal::entityManager()->getStorageController($instance->entity_type)->fieldPurgeData($entity, $instance);
       }
     }
     else {
@@ -299,37 +290,6 @@ function field_purge_batch($batch_size) {
 }
 
 /**
- * Purges the field data for a single field on a single pseudo-entity.
- *
- * This is basically the same as field_attach_delete() except it only applies to
- * a single field. The entity itself is not being deleted, and it is quite
- * possible that other field data will remain attached to it.
- *
- * @param \Drupal\Core\Entity\EntityInterface $entity
- *   The pseudo-entity whose field data is being purged.
- * @param $field
- *   The (possibly deleted) field whose data is being purged.
- * @param $instance
- *   The deleted field instance whose data is being purged.
- */
-function field_purge_data(EntityInterface $entity, $field, $instance) {
-  foreach ($entity->{$field->id()} as $value) {
-    $definition = _field_generate_entity_field_definition($field, $instance);
-    $items = \Drupal::typedData()->create($definition, $value, $field->id(), $entity);
-    $items->delete();
-  }
-
-  // Tell the field storage system to purge the data.
-  module_invoke($field['storage']['module'], 'field_storage_purge', $entity, $field, $instance);
-
-  // Let other modules act on purging the data.
-  foreach (module_implements('field_attach_purge') as $module) {
-    $function = $module . '_field_attach_purge';
-    $function($entity, $field, $instance);
-  }
-}
-
-/**
  * Purges a field instance record from the database.
  *
  * This function assumes all data for the instance has already been purged and
@@ -340,7 +300,7 @@ function field_purge_data(EntityInterface $entity, $field, $instance) {
  */
 function field_purge_instance($instance) {
   // Notify the storage engine.
-  $field = field_info_field_by_id($instance['field_id']);
+  $field = $instance->getField();
   module_invoke($field['storage']['module'], 'field_storage_purge_instance', $instance);
 
   $state = Drupal::state();
diff --git a/core/modules/field/field.info.inc b/core/modules/field/field.info.inc
index b6b2a95..cee50b2 100644
--- a/core/modules/field/field.info.inc
+++ b/core/modules/field/field.info.inc
@@ -42,77 +42,10 @@ function field_info_cache_clear() {
   Drupal::typedData()->clearCachedDefinitions();
   Drupal::service('plugin.manager.entity.field.field_type')->clearCachedDefinitions();
 
-  _field_info_collate_types_reset();
   Field::fieldInfo()->flush();
 }
 
 /**
- * Collates all information on field types, widget types and related structures.
- *
- * @return
- *   An associative array containing:
- *   - 'storage types': Array of hook_field_storage_info() results, keyed by
- *     storage type names. Each element has the following components: label,
- *     description, and settings from hook_field_storage_info(), as well as
- *     module, giving the module that exposes the storage type.
- *
- * @see _field_info_collate_types_reset()
- */
-function _field_info_collate_types() {
-  $language_interface = language(Language::TYPE_INTERFACE);
-
-  // Use the advanced drupal_static() pattern, since this is called very often.
-  static $drupal_static_fast;
-
-  if (!isset($drupal_static_fast)) {
-    $drupal_static_fast['field_info_collate_types'] = &drupal_static(__FUNCTION__);
-  }
-  $info = &$drupal_static_fast['field_info_collate_types'];
-
-  // The _info() hooks invoked below include translated strings, so each
-  // language is cached separately.
-  $langcode = $language_interface->id;
-
-  if (!isset($info)) {
-    if ($cached = cache('field')->get("field_info_types:$langcode")) {
-      $info = $cached->data;
-    }
-    else {
-      $info = array(
-        'storage types' => array(),
-      );
-
-      // Populate storage types.
-      foreach (module_implements('field_storage_info') as $module) {
-        $storage_types = (array) module_invoke($module, 'field_storage_info');
-        foreach ($storage_types as $name => $storage_info) {
-          // Provide defaults.
-          $storage_info += array(
-            'settings' => array(),
-          );
-          $info['storage types'][$name] = $storage_info;
-          $info['storage types'][$name]['module'] = $module;
-        }
-      }
-      drupal_alter('field_storage_info', $info['storage types']);
-
-      cache('field')->set("field_info_types:$langcode", $info, CacheBackendInterface::CACHE_PERMANENT, array('field_info_types' => TRUE));
-    }
-  }
-
-  return $info;
-}
-
-/**
- * Clears collated information on field and widget types and related structures.
- */
-function _field_info_collate_types_reset() {
-  drupal_static_reset('_field_info_collate_types');
-  // Clear all languages.
-  cache('field')->deleteTags(array('field_info_types' => TRUE));
-}
-
-/**
  * Determines the behavior of a widget with respect to an operation.
  *
  * @param string $op
@@ -225,31 +158,6 @@ function field_info_formatter_types($formatter_type = NULL) {
 }
 
 /**
- * Returns information about field storage from hook_field_storage_info().
- *
- * @param $storage_type
- *   (optional) A storage type name. If omitted, all storage types will be
- *   returned.
- *
- * @return
- *   Either a storage type description, as provided by
- *   hook_field_storage_info(), or an array of all existing storage types, keyed
- *   by storage type name.
- */
-function field_info_storage_types($storage_type = NULL) {
-  $info = _field_info_collate_types();
-  $storage_types = $info['storage types'];
-  if ($storage_type) {
-    if (isset($storage_types[$storage_type])) {
-      return $storage_types[$storage_type];
-    }
-  }
-  else {
-    return $storage_types;
-  }
-}
-
-/**
  * Returns all field definitions.
  *
  * Use of this function should be avoided when possible, since it loads and
@@ -281,8 +189,10 @@ function field_info_fields() {
 }
 
 /**
- * Returns data about an individual field, given a field name.
+ * Returns data about an individual field.
  *
+ * @param $entity_type
+ *   The entity type.
  * @param $field_name
  *   The name of the field to retrieve. $field_name can only refer to a
  *   non-deleted, active field. For deleted fields, use
@@ -300,8 +210,8 @@ function field_info_fields() {
  * @deprecated as of Drupal 8.0. Use
  *   Field::fieldInfo()->getField($field_name).
  */
-function field_info_field($field_name) {
-  return Field::fieldInfo()->getField($field_name);
+function field_info_field($entity_type, $field_name) {
+  return Field::fieldInfo()->getField($entity_type, $field_name);
 }
 
 /**
@@ -541,21 +451,5 @@ function field_info_formatter_settings($type) {
 }
 
 /**
- * Returns a field storage type's default settings.
- *
- * @param $type
- *   A field storage type name.
- *
- * @return
- *   The storage type's default settings, as provided by
- *   hook_field_storage_info(), or an empty array if type or settings are
- *   undefined.
- */
-function field_info_storage_settings($type) {
-  $info = field_info_storage_types($type);
-  return isset($info['settings']) ? $info['settings'] : array();
-}
-
-/**
  * @} End of "defgroup field_info".
  */
diff --git a/core/modules/field/field.install b/core/modules/field/field.install
index b425169..abdda29 100644
--- a/core/modules/field/field.install
+++ b/core/modules/field/field.install
@@ -6,6 +6,7 @@
  */
 
 use Drupal\Component\Uuid\Uuid;
+use Drupal\Core\Entity\DatabaseStorageController;
 use Drupal\field\Plugin\Core\Entity\Field;
 
 /**
@@ -25,7 +26,6 @@ function _update_8003_field_create_field(array &$field_config) {
   // Merge in default values.
   $field_config += array(
     'uuid' => $uuid->generate(),
-    'entity_types' => array(),
     'cardinality' => 1,
     'translatable' => FALSE,
     'locked' => FALSE,
@@ -36,23 +36,10 @@ function _update_8003_field_create_field(array &$field_config) {
     'langcode' => 'und',
   );
 
-  // Set the storage.
-  $field_config['storage'] = array(
-    'type' => 'field_sql_storage',
-    'module' => 'field_sql_storage',
-    'active' => TRUE,
-    'settings' => array(),
-  );
-
   // Save in config.
   Drupal::config('field.field.' . $field_config['id'])
     ->setData($field_config)
     ->save();
-
-  // Create storage for the field. This requires a field entity, but cannot use
-  // the regular entity_create() function here.
-  $field_entity = new Field($field_config);
-  field_sql_storage_field_storage_create_field($field_entity);
 }
 
 /**
@@ -65,10 +52,12 @@ function _update_8003_field_create_field(array &$field_config) {
  *   An array of field properties.
  * @param array $instance_config
  *   An array of field instance properties.
+ * @param bool $first
+ *   TRUE if this is the first instance of the field. Defaults to TRUE.
  *
  * @ingroup update_api
  */
-function _update_8003_field_create_instance(array $field_config, array &$instance_config) {
+function _update_8003_field_create_instance(array $field_config, array &$instance_config, $first = TRUE) {
   $uuid = new Uuid();
 
   // Merge in defaults.
@@ -90,6 +79,74 @@ function _update_8003_field_create_instance(array $field_config, array &$instanc
   Drupal::config('field.instance.' . $instance_config['id'])
     ->setData($instance_config)
     ->save();
+  if ($first) {
+    $schema = DatabaseStorageController::_fieldSqlSchema(new Field($field_config));
+    foreach ($schema as $name => $table) {
+      db_create_table($name, $table);
+    }
+  }
+}
+
+/**
+ * Writes field data directly to SQL storage.
+ *
+ *
+ * @param string $entity_type
+ * @param string $bundle
+ * @param int $entity_id
+ * @param int $revision_id
+ * @param int $field_name
+ * @param array $data
+ *
+ * @ingroup update_api
+ */
+function _update_8000_field_sql_storage_write($entity_type, $bundle, $entity_id, $revision_id, $field_name, array $data) {
+  $table_name = "field_data_{$field_name}";
+  $revision_name = "field_revision_{$field_name}";
+
+  db_delete($table_name)
+    ->condition('entity_type', $entity_type)
+    ->condition('entity_id', $entity_id)
+    ->execute();
+  db_delete($revision_name)
+    ->condition('entity_type', $entity_type)
+    ->condition('entity_id', $entity_id)
+    ->condition('revision_id', $revision_id)
+    ->execute();
+
+  $columns = array();
+  foreach ($data as $langcode => $items) {
+    foreach ($items as $delta => $item) {
+      $record = array(
+        'entity_type' => $entity_type,
+        'entity_id' => $entity_id,
+        'revision_id' => $revision_id,
+        'bundle' => $bundle,
+        'delta' => $delta,
+        'langcode' => $langcode,
+      );
+      foreach ($item as $column => $value) {
+        $record[_field_sql_storage_columnname($field_name, $column)] = $value;
+      }
+
+      $records[] = $record;
+      // Record the columns used.
+      $columns += $record;
+    }
+  }
+
+  if ($columns) {
+    $query = db_insert($table_name)->fields(array_keys($columns));
+    $revision_query = db_insert($revision_name)->fields(array_keys($columns));
+    foreach ($records as $record) {
+      $query->values($record);
+      if ($revision_id) {
+        $revision_query->values($record);
+      }
+    }
+    $query->execute();
+    $revision_query->execute();
+  }
 }
 
 /**
@@ -250,7 +307,7 @@ function field_update_8003() {
   $field_data = array();
 
   // Migrate field definitions.
-  $records = db_query("SELECT * FROM {field_config}")->fetchAll(PDO::FETCH_ASSOC);
+  $records = db_query("SELECT DISTINCT entity_type, fc.* FROM {field_config} fc INNER JOIN {field_config_instance} fci ON fc.field_id = fci.field_id")->fetchAll(PDO::FETCH_ASSOC);
   foreach ($records as $record) {
     $record['data'] = unserialize($record['data']);
 
@@ -260,17 +317,11 @@ function field_update_8003() {
       'type' => $record['type'],
       'module' => $record['module'],
       'active' => $record['active'],
+      'entity_type' => $record['entity_type'],
       'settings' => $record['data']['settings'],
-      'storage' => array(
-        'type' => $record['storage_type'],
-        'module' => $record['storage_module'],
-        'active' => $record['storage_active'],
-        'settings' => $record['data']['storage']['settings'],
-      ),
       'locked' => $record['locked'],
       'cardinality' => $record['cardinality'],
       'translatable' => $record['translatable'],
-      'entity_types' => $record['data']['entity_types'],
       'indexes' => $record['data']['indexes'] ?: array(),
       'status' => 1,
       'langcode' => 'und',
@@ -283,26 +334,28 @@ function field_update_8003() {
 
     // Save in either config or state.
     if (!$record['deleted']) {
-      Drupal::config('field.field.' . $config['id'])
+      Drupal::config('field.field.' . $config['entity_type'] .'.' . $config['id'])
         ->setData($config)
         ->save();
     }
     else {
       $config['deleted'] = TRUE;
       $deleted_fields[$config['uuid']] = $config;
+      // This will not be saved but the DatabaseStorageController helpers need
+      // the field object.
+      $field = new Field($config);
       // Additionally, rename the data tables for deleted fields. Technically
       // this would belong in an update in field_sql_storage.module, but it is
-      // easier to do it now, when the old numeric ID is available.
-      if ($config['storage']['type'] == 'field_sql_storage') {
-        $field = new Field($config);
-        $tables = array(
-          "field_deleted_data_{$record['id']}" => _field_sql_storage_tablename($field),
-          "field_deleted_revision_{$record['id']}" => _field_sql_storage_revision_tablename($field),
-        );
-        foreach ($tables as $table_old => $table_new) {
-          if (db_table_exists($table_old)) {
-            db_rename_table($table_old, $table_new);
-          }
+      // easier to do it now, when the old numeric ID is available. Use an
+      // old_ prefix because the real tables will be created when we split by
+      // entity type.
+      $tables = array(
+        "field_deleted_data_{$record['id']}" => 'old_' . DatabaseStorageController::_fieldTableName($field),
+        "field_deleted_revision_{$record['id']}" => 'old_' . DatabaseStorageController::_fieldRevisionTableName($field),
+      );
+      foreach ($tables as $table_old => $table_new) {
+        if (db_table_exists($table_old)) {
+          db_rename_table($table_old, $table_new);
         }
       }
     }
@@ -411,6 +464,71 @@ function field_update_8005() {
     ->save();
 }
 
+
+/**
+ * Splits the field storage tables by entity type and also migrate langcode.
+ */
+function field_update_8006(&$sandbox) {
+  // Get field definitions from config, and deleted fields from state system.
+  $config_names = config_get_storage_names_with_prefix('field.field');
+  $deleted_fields = Drupal::state()->get('field.field.deleted') ?: array();
+  // Ditch UUID keys, we will iterate through deleted fields using a numeric
+  // index.
+  $deleted_fields = array_values($deleted_fields);
+
+  if (empty($config_names) && empty($deleted_fields)) {
+    return;
+  }
+
+  if (!isset($sandbox['index'])) {
+    $sandbox['index'] = 0;
+    $sandbox['max'] = count($config_names) + count($deleted_fields);
+  }
+
+  // Retrieve the next field definition. When the index exceeds the number of
+  // 'configuration' fields, use it to iterate on deleted fields.
+  if (isset($config_names[$sandbox['index']])) {
+    $field_config = config($config_names[$sandbox['index']])->get();
+  }
+  else {
+    $field_config = $deleted_fields[$sandbox['index'] - count($config_names)];
+  }
+
+  $field = new Field($field_config);
+  $tables = array(
+    DatabaseStorageController::_fieldTableName($field),
+    DatabaseStorageController::_fieldRevisionTableName($field),
+  );
+  foreach ($tables as $table) {
+    $original_table = empty($field_config['deleted']) ? 'field_data_' . $field_config['id'] : 'old_' . $table;
+    if (db_table_exists($original_table)) {
+      if (!db_table_exists($table)) {
+        $schema = DatabaseStorageController::_fieldSqlSchema($field);
+        foreach ($schema as $name => $field_table) {
+          db_create_table($name, $field_table);
+        }
+      }
+      $from_fields = array('bundle', 'deleted', 'entity_id', 'revision_id', 'language', 'delta');
+      $insert_fields = array('bundle', 'deleted', 'entity_id', 'revision_id', 'langcode', 'delta');
+      foreach ($field_config['columns'] as $column) {
+        $sql_column = DatabaseStorageController::_fieldColumnName($field, $column);
+        $from_fields[] = $sql_column;
+        $insert_fields[] = $sql_column;
+      }
+      $from_query = db_select($original_table)
+        ->fields($from_fields)
+        ->condition('entity_type', $field_config['entity_type']);
+      db_insert($table)
+        ->fields($insert_fields)
+        ->fromQuery($from_query)
+        ->execute();
+    }
+  }
+
+  $sandbox['index']++;
+  $sandbox['#finished'] = empty($sandbox['max']) ? 1 : ($sandbox['index'] / $sandbox['max']);
+}
+
 /**
  * @} End of "addtogroup updates-7.x-to-8.x".
  * The next series of updates should start at 9000.
diff --git a/core/modules/field/field.module b/core/modules/field/field.module
index 92a2c45..bb34626 100644
--- a/core/modules/field/field.module
+++ b/core/modules/field/field.module
@@ -255,7 +255,7 @@ function field_populate_default_values(EntityInterface $entity, $langcode = NULL
   $entity_type = $entity->entityType();
   $langcode = $langcode ?: $entity->language()->id;
   foreach (field_info_instances($entity_type, $entity->bundle()) as $field_name => $instance) {
-    $field = field_info_field($field_name);
+    $field = $instance->getField();
     $field_langcode = field_is_translatable($entity_type, $field) ? $langcode : Language::LANGCODE_NOT_SPECIFIED;
     // We need to preserve existing values.
     if (empty($entity->{$field_name}) || !array_key_exists($field_langcode, $entity->{$field_name})) {
@@ -306,7 +306,7 @@ function field_entity_field_info($entity_type) {
 function _field_generate_entity_field_definition(FieldInterface $field, FieldInstanceInterface $instance = NULL) {
   // @todo: Allow for adding field type settings.
   $definition = array(
-    'label' => t('Field !name', array('!name' => $field->id())),
+    'label' => t('Field !name', array('!name' => $field->getFieldName())),
     'type' => 'field_item:' . $field->type,
     'list' => TRUE,
     'configurable' => TRUE,
@@ -418,24 +418,8 @@ function field_sync_field_status() {
   // modules.
   $changed = array();
   $modules = $module_handler->getModuleList();
-  foreach ($modules as $module => $module_info) {
-    // Collect storage backends exposed by the module.
-    $storage_types = (array) $module_handler->invoke($module, 'field_storage_info');
-
-    if ($storage_types) {
-      foreach ($fields as $uuid => &$field) {
-        // Associate storage backends.
-        if (isset($storage_types[$field['storage']['type']]) && ($field['storage']['module'] !== $module || !$field['storage']['active'])) {
-          $field['storage']['module'] = $module;
-          $field['storage']['active'] = TRUE;
-          $changed[$uuid] = $field;
-        }
-      }
-    }
-  }
-
   $field_types = Drupal::service('plugin.manager.entity.field.field_type')->getDefinitions();
-  // Set fields with missing field type or storage modules to inactive.
+  // Set fields with missing field type modules to inactive.
   foreach ($fields as $uuid => &$field) {
     // Associate field types.
     if (isset($field_types[$field['type']]) && ($field['module'] != $field_types[$field['type']]['module'] || !$field['active'])) {
@@ -447,11 +431,6 @@ function field_sync_field_status() {
       $field['active'] = FALSE;
       $changed[$uuid] = $field;
     }
-    // Disassociate storage backends.
-    if (!isset($modules[$field['storage']['module']]) && $field['storage']['active']) {
-      $field['storage']['active'] = FALSE;
-      $changed[$uuid] = $field;
-    }
   }
 
   // Store the updated field definitions.
@@ -463,8 +442,6 @@ function field_sync_field_status() {
       Drupal::config('field.field.' . $field['id'])
         ->set('module', $field['module'])
         ->set('active', $field['active'])
-        ->set('storage.module', $field['storage']['module'])
-        ->set('storage.active', $field['storage']['active'])
         ->save();
     }
   }
@@ -695,7 +672,7 @@ function field_view_value(EntityInterface $entity, $field_name, $item, $display
   // Ensure we are working with a BC mode entity.
   $entity = $entity->getBCEntity();
 
-  if ($field = field_info_field($field_name)) {
+  if ($field = field_info_field($entity->entityType(), $field_name)) {
     // Determine the langcode that will be used by language fallback.
     $langcode = field_language($entity, $field_name, $langcode);
 
@@ -785,7 +762,7 @@ function field_view_field(EntityInterface $entity, $field_name, $display_options
     $view_mode = '_custom';
     // hook_field_attach_display_alter() needs to receive the 'prepared'
     // $display_options, so we cannot let preparation happen internally.
-    $field = field_info_field($field_name);
+    $field = field_info_field($entity_type, $field_name);
     $formatter_manager = drupal_container()->get('plugin.manager.field.formatter');
     $display_options = $formatter_manager->prepareConfiguration($field['type'], $display_options);
     $formatter = $formatter_manager->getInstance(array(
diff --git a/core/modules/field/field.views.inc b/core/modules/field/field.views.inc
index 5a1f4f3..f78872f 100644
--- a/core/modules/field/field.views.inc
+++ b/core/modules/field/field.views.inc
@@ -8,6 +8,8 @@
  */
 
 use Drupal\Component\Utility\NestedArray;
+use Drupal\Core\Entity\DatabaseStorageController;
+use Drupal\field\FieldInterface;
 
 /**
  * Implements hook_views_data().
@@ -17,21 +19,19 @@
  */
 function field_views_data() {
   $data = array();
+  $module_handler = Drupal::moduleHandler();
   foreach (field_info_fields() as $field) {
-    if ($field['storage']['type'] != 'field_sql_storage') {
-      continue;
-    }
+    if ($sql_entity_types = _field_views_get_sql_entity_types($field)) {
+      $result = (array) $module_handler->invoke($field['module'], 'field_views_data', array($field, $sql_entity_types));
 
-    $module = $field['module'];
-    $result = (array) module_invoke($module, 'field_views_data', $field);
+      if (empty($result)) {
+        $result = field_views_field_default_views_data($field, $sql_entity_types);
+      }
+      $module_handler->alter('field_views_data', $result, $field, $sql_entity_types);
 
-    if (empty($result)) {
-      $result = field_views_field_default_views_data($field);
-    }
-    Drupal::moduleHandler()->alter('field_views_data', $result, $field, $module);
-
-    if (is_array($result)) {
-      $data = NestedArray::mergeDeep($result, $data);
+      if (is_array($result)) {
+        $data = NestedArray::mergeDeep($result, $data);
+      }
     }
   }
 
@@ -48,18 +48,42 @@ function field_views_data() {
  */
 function field_views_data_alter(&$data) {
   foreach (field_info_fields() as $field) {
-    if ($field['storage']['type'] != 'field_sql_storage') {
-      continue;
-    }
-
-    $function = $field['module'] . '_field_views_data_views_data_alter';
-    if (function_exists($function)) {
-      $function($data, $field);
+    if ($sql_entity_types = _field_views_get_sql_entity_types($field)) {
+      $function = $field['module'] . '_field_views_data_views_data_alter';
+      if (function_exists($function)) {
+        $function($data, $field, $sql_entity_types);
+      }
     }
   }
 }
 
 /**
+ * Returns the SQL-based entity types where the field appears in.
+ *
+ * @param \Drupal\field\FieldInterface $field
+ *   The field definition.
+ *
+ * @return array
+ *   The array of entity types using DatabaseStorageController where the field
+ *   appears in.
+ */
+function _field_views_get_sql_entity_types(FieldInterface $field) {
+  $sql_entity_types = array();
+  $entity_manager = Drupal::entityManager();
+  foreach ($field['bundles'] as $entity_type => $bundles) {
+    try {
+      if ($entity_manager->getStorageController($entity_type) instanceof DatabaseStorageController) {
+        $sql_entity_types[] = $entity_type;
+      }
+    }
+    catch (\InvalidArgumentException $e) {
+      // Disabled entity type, nothing to do.
+    }
+  }
+  return $sql_entity_types;
+}
+
+/**
  * Returns the label of a certain field.
  *
  * Therefore it looks up in all bundles to find the most used instance.
@@ -89,18 +113,22 @@ function field_views_field_label($field_name) {
 /**
  * Default views data implementation for a field.
  */
-function field_views_field_default_views_data($field) {
+function field_views_field_default_views_data(FieldInterface $field, $sql_entity_types) {
+  // If the field had no instances in the SQL storage then there is nothing to be done.
+  if (!$sql_entity_types) {
+    return array();
+  }
   $field_types = field_info_field_types();
 
   // Check the field module is available.
   if (!isset($field_types[$field['type']])) {
-    return;
+    return array();
   }
 
   $data = array();
 
-  $current_table = _field_sql_storage_tablename($field);
-  $revision_table = _field_sql_storage_revision_tablename($field);
+  $current_table = DatabaseStorageController::_fieldTableName($field);
+  $revision_table = DatabaseStorageController::_fieldRevisionTableName($field);
 
   // The list of entity:bundle that this field is used in.
   $bundles_names = array();
@@ -113,35 +141,36 @@ function field_views_field_default_views_data($field) {
   $group_name = count($field['bundles']) > 1 ? t('Field') : NULL;
 
   // Build the relationships between the field table and the entity tables.
-  foreach ($field['bundles'] as $entity => $bundles) {
-    $entity_info = entity_get_info($entity);
-    $groups[$entity] = $entity_info['label'];
+  $entity_manager = Drupal::entityManager();
+  foreach ($sql_entity_types as $entity_type) {
+    $entity_info = $entity_manager->getDefinition($entity_type);
+    $groups[$entity_type] = $entity_info['label'];
 
     // Override Node to Content.
-    if ($groups[$entity] == t('Node')) {
-      $groups[$entity] = t('Content');
+    if ($groups[$entity_type] == t('Node')) {
+      $groups[$entity_type] = t('Content');
     }
 
     // If only one bundle use this as the default name.
     if (empty($group_name)) {
-      $group_name = $groups[$entity];
+      $group_name = $groups[$entity_type];
     }
 
     if (!isset($entity_info['base_table'])) {
       continue;
     }
-    $entity_tables[$entity_info['base_table']] = $entity;
-    $current_tables[$entity] = $entity_info['base_table'];
+    $entity_tables[$entity_info['base_table']] = $entity_type;
+    $current_tables[$entity_type] = $entity_info['base_table'];
     if (isset($entity_info['revision_table'])) {
-      $entity_tables[$entity_info['revision_table']] = $entity;
-      $revision_tables[$entity] = $entity_info['revision_table'];
+      $entity_tables[$entity_info['revision_table']] = $entity_type;
+      $revision_tables[$entity_type] = $entity_info['revision_table'];
     }
 
     $data[$current_table]['table']['join'][$entity_info['base_table']] = array(
       'left_field' => $entity_info['entity_keys']['id'],
       'field' => 'entity_id',
       'extra' => array(
-        array('field' => 'entity_type', 'value' => $entity),
+        array('field' => 'entity_type', 'value' => $entity_type),
         array('field' => 'deleted', 'value' => 0, 'numeric' => TRUE),
       ),
     );
@@ -151,7 +180,7 @@ function field_views_field_default_views_data($field) {
         'left_field' => $entity_info['entity_keys']['revision'],
         'field' => 'revision_id',
         'extra' => array(
-          array('field' => 'entity_type', 'value' => $entity),
+          array('field' => 'entity_type', 'value' => $entity_type),
           array('field' => 'deleted', 'value' => 0, 'numeric' => TRUE),
         ),
       );
@@ -159,8 +188,8 @@ function field_views_field_default_views_data($field) {
       $supports_revisions = TRUE;
     }
 
-    foreach ($bundles as $bundle) {
-      $bundles_names[] = t('@entity:@bundle', array('@entity' => $entity, '@bundle' => $bundle));
+    foreach ($field['bundles'][$entity_type] as $bundle) {
+      $bundles_names[] = t('@entity:@bundle', array('@entity' => $entity_type, '@bundle' => $bundle));
     }
   }
 
@@ -172,7 +201,7 @@ function field_views_field_default_views_data($field) {
 
   $add_fields = array('delta', 'langcode', 'bundle');
   foreach ($field['columns'] as $column_name => $attributes) {
-    $add_fields[] = _field_sql_storage_columnname($field['field_name'], $column_name);
+    $add_fields[] = DatabaseStorageController::_fieldColumnName($field, $column_name);
   }
 
   // Note: we don't have a label available here, because we are at the field
@@ -243,6 +272,7 @@ function field_views_field_default_views_data($field) {
       'table' => $table,
       'id' => 'field',
       'field_name' => $field['field_name'],
+      'entity_type' => $field['entity_type'],
       // Provide a real field for group by.
       'real field' => $column . '_' . $real_field,
       'additional fields' => $add_fields,
@@ -296,10 +326,11 @@ function field_views_field_default_views_data($field) {
       else {
         $group = t('@group (historical data)', array('@group' => $group_name));
       }
-      $column_real_name = $field['storage_details']['sql'][$type][$table][$column];
+      $column_real_name = DatabaseStorageController::_fieldColumnName($field, $column);
 
       // Load all the fields from the table by default.
-      $additional_fields = array_values($field['storage_details']['sql'][$type][$table]);
+      $field_sql_schema = DatabaseStorageController::_fieldSqlSchema($field);
+      $additional_fields = array_keys($field_sql_schema[$current_table]['fields']);
 
       $data[$table][$column_real_name] = array(
         'group' => $group,
@@ -341,6 +372,7 @@ function field_views_field_default_views_data($field) {
         'id' => $argument,
         'additional fields' => $additional_fields,
         'field_name' => $field['field_name'],
+        'entity_type' => $field['entity_type'],
         'empty field name' => t('- No value -'),
       );
       $data[$table][$column_real_name]['filter'] = array(
@@ -349,6 +381,7 @@ function field_views_field_default_views_data($field) {
         'id' => $filter,
         'additional fields' => $additional_fields,
         'field_name' => $field['field_name'],
+        'entity_type' => $field['entity_type'],
         'allow empty' => TRUE,
       );
       if (!empty($allow_sort)) {
@@ -358,6 +391,7 @@ function field_views_field_default_views_data($field) {
           'id' => $sort,
           'additional fields' => $additional_fields,
           'field_name' => $field['field_name'],
+          'entity_type' => $field['entity_type'],
         );
       }
 
@@ -382,6 +416,7 @@ function field_views_field_default_views_data($field) {
           'additional fields' => $additional_fields,
           'empty field name' => t('- No value -'),
           'field_name' => $field['field_name'],
+          'entity_type' => $field['entity_type'],
         );
         $data[$table]['delta']['filter'] = array(
           'field' => 'delta',
@@ -389,6 +424,7 @@ function field_views_field_default_views_data($field) {
           'id' => 'numeric',
           'additional fields' => $additional_fields,
           'field_name' => $field['field_name'],
+          'entity_type' => $field['entity_type'],
           'allow empty' => TRUE,
         );
         $data[$table]['delta']['sort'] = array(
@@ -397,6 +433,7 @@ function field_views_field_default_views_data($field) {
           'id' => 'standard',
           'additional fields' => $additional_fields,
           'field_name' => $field['field_name'],
+          'entity_type' => $field['entity_type'],
         );
       }
 
@@ -421,6 +458,7 @@ function field_views_field_default_views_data($field) {
           'additional fields' => $additional_fields,
           'empty field name' => t('<No value>'),
           'field_name' => $field['field_name'],
+          'entity_type' => $field['entity_type'],
         );
         $data[$table]['language']['filter'] = array(
           'field' => 'language',
@@ -428,6 +466,7 @@ function field_views_field_default_views_data($field) {
           'id' => 'language',
           'additional fields' => $additional_fields,
           'field_name' => $field['field_name'],
+          'entity_type' => $field['entity_type'],
           'allow empty' => TRUE,
         );
         $data[$table]['language']['sort'] = array(
@@ -436,6 +475,7 @@ function field_views_field_default_views_data($field) {
           'id' => 'standard',
           'additional fields' => $additional_fields,
           'field_name' => $field['field_name'],
+          'entity_type' => $field['entity_type'],
         );
       }
     }
@@ -447,8 +487,8 @@ function field_views_field_default_views_data($field) {
 /**
  * Have a different filter handler for lists. This should allow to select values of the list.
  */
-function list_field_views_data($field) {
-  $data = field_views_field_default_views_data($field);
+function list_field_views_data($field, $sql_entity_types) {
+  $data = field_views_field_default_views_data($field, $sql_entity_types);
   foreach ($data as $table_name => $table_data) {
     foreach ($table_data as $field_name => $field_data) {
       if (isset($field_data['filter']) && $field_name != 'delta') {
diff --git a/core/modules/field/lib/Drupal/field/FieldInfo.php b/core/modules/field/lib/Drupal/field/FieldInfo.php
index e7e46b9..7a1a353 100644
--- a/core/modules/field/lib/Drupal/field/FieldInfo.php
+++ b/core/modules/field/lib/Drupal/field/FieldInfo.php
@@ -180,7 +180,7 @@ public function getFieldMap() {
     // Get active fields.
     foreach (config_get_storage_names_with_prefix('field.field.') as $config_id) {
       $field_config = $this->config->get($config_id)->get();
-      if ($field_config['active'] && $field_config['storage']['active']) {
+      if ($field_config['active']) {
         $fields[$field_config['uuid']] = $field_config;
       }
     }
@@ -192,8 +192,8 @@ public function getFieldMap() {
       // entity types.
       if (isset($fields[$field_uuid])) {
         $field = $fields[$field_uuid];
-        $map[$field['id']]['bundles'][$instance_config['entity_type']][] = $instance_config['bundle'];
-        $map[$field['id']]['type'] = $field['type'];
+        $map[$field['name']]['bundles'][$instance_config['entity_type']][] = $instance_config['bundle'];
+        $map[$field['name']]['type'] = $field['type'];
       }
     }
 
@@ -233,7 +233,7 @@ public function getFields() {
     // Fill the name/ID map.
     foreach ($this->fieldsById as $field) {
       if (!$field['deleted']) {
-        $this->fieldIdsByName[$field['id']] = $field['uuid'];
+        $this->fieldIdsByName[$field->entity_type][$field->name] = $field['uuid'];
       }
     }
 
@@ -269,7 +269,7 @@ public function getInstances($entity_type = NULL) {
         $this->getFields();
 
         foreach (field_read_instances() as $instance) {
-          $field = $this->getField($instance['field_name']);
+          $field = $this->getField($instance['entity_type'], $instance['field_name']);
           $instance = $this->prepareInstance($instance, $field['type']);
           $this->bundleInstances[$instance['entity_type']][$instance['bundle']][$instance['field_name']] = $instance;
         }
@@ -294,36 +294,38 @@ public function getInstances($entity_type = NULL) {
    *
    * This method only retrieves active, non-deleted fields.
    *
+   * @param $entity_type
+   *   The entity type.
    * @param $field_name
    *   The field name.
    *
    * @return
    *   The field definition, or NULL if no field was found.
    */
-  public function getField($field_name) {
+  public function getField($entity_type, $field_name) {
     // Read from the "static" cache.
-    if (isset($this->fieldIdsByName[$field_name])) {
-      $field_id = $this->fieldIdsByName[$field_name];
+    if (isset($this->fieldIdsByName[$entity_type][$field_name])) {
+      $field_id = $this->fieldIdsByName[$entity_type][$field_name];
       return $this->fieldsById[$field_id];
     }
-    if (isset($this->unknownFields[$field_name])) {
+    if (isset($this->unknownFields[$entity_type][$field_name])) {
       return;
     }
 
     // Do not check the (large) persistent cache, but read the definition.
 
     // Cache miss: read from definition.
-    if ($field = field_read_field($field_name)) {
+    if ($field = entity_load('field_entity', $entity_type . '.' . $field_name)) {
       $field = $this->prepareField($field);
 
       // Save in the "static" cache.
       $this->fieldsById[$field['uuid']] = $field;
-      $this->fieldIdsByName[$field['field_name']] = $field['uuid'];
+      $this->fieldIdsByName[$entity_type][$field_name] = $field['uuid'];
 
       return $field;
     }
     else {
-      $this->unknownFields[$field_name] = TRUE;
+      $this->unknownFields[$entity_type][$field_name] = TRUE;
     }
   }
 
@@ -358,7 +360,7 @@ public function getFieldById($field_id) {
       // Store in the static cache.
       $this->fieldsById[$field['uuid']] = $field;
       if (!$field['deleted']) {
-        $this->fieldIdsByName[$field['field_name']] = $field['uuid'];
+        $this->fieldIdsByName[$field->entity_type][$field->name] = $field['uuid'];
       }
 
       return $field;
@@ -400,7 +402,7 @@ public function getBundleInstances($entity_type, $bundle) {
         if (!isset($this->fieldsById[$field['uuid']])) {
           $this->fieldsById[$field['uuid']] = $field;
           if (!$field['deleted']) {
-            $this->fieldIdsByName[$field['field_name']] = $field['uuid'];
+            $this->fieldIdsByName[$field->entity_type][$field->name] = $field['uuid'];
           }
         }
       }
@@ -430,29 +432,31 @@ public function getBundleInstances($entity_type, $bundle) {
       $config_ids = array();
       foreach ($this->getFieldMap() as $field_name => $field_data) {
         if (isset($field_data['bundles'][$entity_type]) && in_array($bundle, $field_data['bundles'][$entity_type])) {
-          $config_ids[$field_name] = "$entity_type.$bundle.$field_name";
+          $config_ids["$entity_type.$field_name"] = "$entity_type.$bundle.$field_name";
         }
       }
 
       // Load and prepare the corresponding fields and instances entities.
       if ($config_ids) {
+        // Place the fields in our global "static".
         $loaded_fields = entity_load_multiple('field_entity', array_keys($config_ids));
-        $loaded_instances = entity_load_multiple('field_instance', array_values($config_ids));
-
-        foreach ($loaded_instances as $instance) {
-          $field = $loaded_fields[$instance['field_name']];
-
-          $instance = $this->prepareInstance($instance, $field['type']);
-          $instances[$field['field_name']] = $instance;
-
-          // If the field is not in our global "static" list yet, add it.
+        foreach ($loaded_fields as $field) {
           if (!isset($this->fieldsById[$field['uuid']])) {
             $field = $this->prepareField($field);
 
             $this->fieldsById[$field['uuid']] = $field;
-            $this->fieldIdsByName[$field['field_name']] = $field['uuid'];
+            $this->fieldIdsByName[$field->entity_type][$field->name] = $field['uuid'];
           }
         }
+
+        // Then collect the instances.
+        $loaded_instances = entity_load_multiple('field_instance', array_values($config_ids));
+        foreach ($loaded_instances as $instance) {
+          $field = $instance->getField();
+
+          $instance = $this->prepareInstance($instance, $field['type']);
+          $instances[$field['field_name']] = $instance;
+        }
       }
     }
 
@@ -554,7 +558,6 @@ public function getBundleExtraFields($entity_type, $bundle) {
   public function prepareField($field) {
     // Make sure all expected field settings are present.
     $field['settings'] += field_info_field_settings($field['type']);
-    $field['storage']['settings'] += field_info_storage_settings($field['storage']['type']);
 
     return $field;
   }
diff --git a/core/modules/field/lib/Drupal/field/FieldInstanceStorageController.php b/core/modules/field/lib/Drupal/field/FieldInstanceStorageController.php
index f9ce249..d40808e 100644
--- a/core/modules/field/lib/Drupal/field/FieldInstanceStorageController.php
+++ b/core/modules/field/lib/Drupal/field/FieldInstanceStorageController.php
@@ -136,7 +136,6 @@ public function loadByProperties(array $conditions = array()) {
     // Translate "do not include inactive fields" into actual conditions.
     if (!$include_inactive) {
       $conditions['field.active'] = TRUE;
-      $conditions['field.storage.active'] = TRUE;
     }
 
     // Collect matching instances.
@@ -162,10 +161,6 @@ public function loadByProperties(array $conditions = array()) {
             $checked_value = $field->active;
             break;
 
-          case 'field.storage.active':
-            $checked_value = $field->storage['active'];
-            break;
-
           case 'field_id':
             $checked_value = $instance->field_uuid;
             break;
diff --git a/core/modules/field/lib/Drupal/field/FieldInterface.php b/core/modules/field/lib/Drupal/field/FieldInterface.php
index 132bc39..8d7edd8 100644
--- a/core/modules/field/lib/Drupal/field/FieldInterface.php
+++ b/core/modules/field/lib/Drupal/field/FieldInterface.php
@@ -45,34 +45,6 @@ public function getSchema();
   public function getColumns();
 
   /**
-   * Returns information about how the storage backend stores the field data.
-   *
-   * The content of the returned value depends on the storage backend, and some
-   * storage backends might provide no information.
-   *
-   * It is strongly discouraged to use this information to perform direct write
-   * operations to the field data storage, bypassing the regular field saving
-   * APIs.
-   *
-   * Example return value for the default field_sql_storage backend:
-   * - 'sql'
-   *   - FIELD_LOAD_CURRENT
-   *     - Table name (string).
-   *       - Table schema (array)
-   *   - FIELD_LOAD_REVISION
-   *     - Table name (string).
-   *       - Table schema (array).
-   *
-   * @return array
-   *   The storage details.
-   *    - The first dimension is a store type (sql, solr, etc).
-   *    - The second dimension indicates the age of the values in the store
-   *      FIELD_LOAD_CURRENT or FIELD_LOAD_REVISION.
-   *    - Other dimensions are specific to the field storage backend.
-   */
-  public function getStorageDetails();
-
-  /**
    * Returns the list of bundles where the field has instances.
    *
    * @return array
diff --git a/core/modules/field/lib/Drupal/field/FieldStorageController.php b/core/modules/field/lib/Drupal/field/FieldStorageController.php
index 41efe60..850d293 100644
--- a/core/modules/field/lib/Drupal/field/FieldStorageController.php
+++ b/core/modules/field/lib/Drupal/field/FieldStorageController.php
@@ -118,7 +118,6 @@ public function loadByProperties(array $conditions = array()) {
     // Translate "do not include inactive instances" into actual conditions.
     if (!$include_inactive) {
       $conditions['active'] = TRUE;
-      $conditions['storage.active'] = TRUE;
     }
 
     // Collect matching fields.
@@ -127,10 +126,6 @@ public function loadByProperties(array $conditions = array()) {
       foreach ($conditions as $key => $value) {
         // Extract the actual value against which the condition is checked.
         switch ($key) {
-          case 'storage.active':
-            $checked_value = $field->storage['active'];
-            break;
-
           case 'field_name';
             $checked_value = $field->id;
             break;
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 1bb1ae4..95cfb3e 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
@@ -57,6 +57,19 @@ class Field extends ConfigEntityBase implements FieldInterface {
   public $id;
 
   /**
+   * The field name.
+   *
+   * This is the name of the property under which the field values are placed in
+   * an entity : $entity-{>$field_id}. The maximum length is
+   * Field:ID_MAX_LENGTH.
+   *
+   * Example: body, field_main_image.
+   *
+   * @var string
+   */
+  public $name;
+
+  /**
    * The field UUID.
    *
    * This is assigned automatically when the field is created.
@@ -66,6 +79,13 @@ class Field extends ConfigEntityBase implements FieldInterface {
   public $uuid;
 
   /**
+   * The name of the entity type the field can be attached to.
+   *
+   * @var string
+   */
+  public $entity_type;
+
+  /**
    * The field type.
    *
    * Example: text, number_integer.
@@ -118,16 +138,6 @@ class Field extends ConfigEntityBase implements FieldInterface {
   public $translatable = FALSE;
 
   /**
-   * The entity types on which the field is allowed to have instances.
-   *
-   * If empty or not specified, the field is allowed to have instances in any
-   * entity type.
-   *
-   * @var array
-   */
-  public $entity_types = array();
-
-  /**
    * Flag indicating whether the field is available for editing.
    *
    * If TRUE, some actions not available though the UI (but are still possible
@@ -142,25 +152,6 @@ class Field extends ConfigEntityBase implements FieldInterface {
   public $locked = FALSE;
 
   /**
-   * The field storage definition.
-   *
-   * An array of key/value pairs identifying the storage backend to use for the
-   * field:
-   * - type: (string) The storage backend used by the field. Storage backends
-   *   are defined by modules that implement hook_field_storage_info().
-   * - settings: (array) A sub-array of key/value pairs of settings. The keys
-   *   and default values are defined by the storage backend in the 'settings'
-   *   entry of hook_field_storage_info().
-   * - module: (string, read-only) The name of the module that implements the
-   *   storage backend.
-   * - active: (integer, read-only) TRUE if the module that implements the
-   *   storage backend is currently enabled, FALSE otherwise.
-   *
-   * @var array
-   */
-  public $storage = array();
-
-  /**
    * The custom storage indexes for the field data storage.
    *
    * This set of indexes is merged with the "default" indexes specified by the
@@ -201,13 +192,6 @@ class Field extends ConfigEntityBase implements FieldInterface {
   protected $schema;
 
   /**
-   * The storage information for the field.
-   *
-   * @var array
-   */
-  protected $storageDetails;
-
-  /**
    * The original field.
    *
    * @var \Drupal\field\Plugin\Core\Entity\Field
@@ -222,8 +206,9 @@ class Field extends ConfigEntityBase implements FieldInterface {
    *   elements will be used to set the corresponding properties on the class;
    *   see the class property documentation for details. Some array elements
    *   have special meanings and a few are required. Special elements are:
-   *   - id: required. As a temporary Backwards Compatibility layer right now,
+   *   - name: required. As a temporary Backwards Compatibility layer right now,
    *     a 'field_name' property can be accepted in place of 'id'.
+   *   - entity_type: required.
    *   - type: required.
    *
    * In most cases, Field entities are created via
@@ -236,21 +221,17 @@ class Field extends ConfigEntityBase implements FieldInterface {
    */
   public function __construct(array $values, $entity_type = 'field_entity') {
     // Check required properties.
+    if (empty($values['name'])) {
+      throw new FieldException('Attempt to create an unnamed field.');
+    }
+    if (!preg_match('/^[_a-z]+[_a-z0-9]*$/', $values['name'])) {
+      throw new FieldException('Attempt to create a field with invalid characters. Only lowercase alphanumeric characters and underscores are allowed, and only lowercase letters and underscore are allowed as the first character');
+    }
     if (empty($values['type'])) {
       throw new FieldException('Attempt to create a field with no type.');
     }
-    // Temporary BC layer: accept both 'id' and 'field_name'.
-    // @todo $field_name and the handling for it will be removed in
-    //   http://drupal.org/node/1953408.
-    if (empty($values['field_name']) && empty($values['id'])) {
-      throw new FieldException('Attempt to create an unnamed field.');
-    }
-    if (empty($values['id'])) {
-      $values['id'] = $values['field_name'];
-      unset($values['field_name']);
-    }
-    if (!preg_match('/^[_a-z]+[_a-z0-9]*$/', $values['id'])) {
-      throw new FieldException('Attempt to create a field with invalid characters. Only lowercase alphanumeric characters and underscores are allowed, and only lowercase letters and underscore are allowed as the first character');
+    if (empty($values['entity_type'])) {
+      throw new FieldException('Attempt to create a field with no entity_type.');
     }
 
     parent::__construct($values, $entity_type);
@@ -259,18 +240,25 @@ public function __construct(array $values, $entity_type = 'field_entity') {
   /**
    * {@inheritdoc}
    */
+  public function id() {
+    return $this->entity_type . '.' . $this->name;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function getExportProperties() {
     $names = array(
       'id',
       'uuid',
       'status',
       'langcode',
+      'name',
+      'entity_type',
       'type',
       'settings',
       'module',
       'active',
-      'entity_types',
-      'storage',
       'locked',
       'cardinality',
       'translatable',
@@ -296,7 +284,7 @@ public function getExportProperties() {
    */
   public function save() {
     // Clear the derived data about the field.
-    unset($this->schema, $this->storageDetails);
+    unset($this->schema);
 
     if ($this->isNew()) {
       return $this->saveNew();
@@ -318,18 +306,20 @@ public function save() {
    *   In case of failures at the configuration storage level.
    */
   protected function saveNew() {
-    $module_handler = \Drupal::moduleHandler();
     $entity_manager = \Drupal::entityManager();
     $storage_controller = $entity_manager->getStorageController($this->entityType);
 
+    // Assign the ID.
+    $this->id = $this->id();
+
     // 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) {
+    if (drupal_strlen($this->name) > static::ID_MAX_LENGTH) {
       throw new FieldException(format_string(
-        'Attempt to create a field with an ID longer than @max characters: %id', array(
+        'Attempt to create a field with an ID longer than @max characters: %name', array(
           '@max' => static::ID_MAX_LENGTH,
-          '%id' => $this->id,
+          '%name' => $this->name,
         )
       ));
     }
@@ -337,17 +327,17 @@ protected function saveNew() {
     // Ensure the field name is unique (we do not care about deleted fields).
     if ($prior_field = $storage_controller->load($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)));
+        'Attempt to create field name %name which already exists and is active.' :
+        'Attempt to create field name %name which already exists, although it is inactive.';
+      throw new FieldException(format_string($message, array('%name' => $this->name)));
     }
 
     // Disallow reserved field names. This can't prevent all field name
     // collisions with existing entity properties, but some is better than
     // none.
     foreach ($entity_manager->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)));
+      if (in_array($this->name, $info['entity_keys'])) {
+        throw new FieldException(format_string('Attempt to create field %name which is reserved by entity type %type.', array('%name' => $this->name, '%type' => $type)));
       }
     }
 
@@ -363,23 +353,8 @@ protected function saveNew() {
     // 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'] = TRUE;
-    // Provide default storage settings.
-    $this->storage['settings'] += $storage_type['settings'];
-
-    // Invoke the storage backend's hook_field_storage_create_field().
-    $module_handler->invoke($this->storage['module'], 'field_storage_create_field', array($this));
+    // Notify the entity storage controller.
+    $entity_manager->getStorageController($this->entity_type)->handleFieldCreate($this);
 
     // Save the configuration.
     $result = parent::save();
@@ -401,7 +376,8 @@ protected function saveNew() {
    */
   protected function saveUpdated() {
     $module_handler = \Drupal::moduleHandler();
-    $storage_controller = \Drupal::entityManager()->getStorageController($this->entityType);
+    $entity_manager = \Drupal::entityManager();
+    $storage_controller = $entity_manager->getStorageController($this->entityType);
 
     $original = $storage_controller->loadUnchanged($this->id());
     $this->original = $original;
@@ -410,11 +386,8 @@ protected function saveUpdated() {
     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.");
+    if ($this->entity_type != $original->entity_type) {
+      throw new FieldException("Cannot change an existing field's entity_type.");
     }
 
     // Make sure all settings are present, so that a complete field definition
@@ -426,11 +399,10 @@ protected function saveUpdated() {
     // invokes hook_field_update_forbid().
     $module_handler->invokeAll('field_update_forbid', array($this, $original));
 
-    // 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));
+    // Notify the storage controller. The controller can reject the definition
+    // update as invalid by raising an exception, which stops execution before
+    // the definition is written to config.
+    $entity_manager->getStorageController($this->entity_type)->handleFieldUpdate($this, $original);
 
     // Save the configuration.
     $result = parent::save();
@@ -444,7 +416,6 @@ protected function saveUpdated() {
    */
   public function delete() {
     if (!$this->deleted) {
-      $module_handler = \Drupal::moduleHandler();
       $instance_controller = \Drupal::entityManager()->getStorageController('field_instance');
       $state = \Drupal::state();
 
@@ -452,7 +423,7 @@ public function delete() {
       $instance_ids = array();
       foreach ($this->getBundles() as $entity_type => $bundles) {
         foreach ($bundles as $bundle) {
-          $instance_ids[] = "$entity_type.$bundle.$this->id";
+          $instance_ids[] = "$entity_type.$bundle.$this->name";
         }
       }
       foreach ($instance_controller->loadMultiple($instance_ids) as $instance) {
@@ -463,9 +434,7 @@ public function delete() {
         $instance->delete(FALSE);
       }
 
-      // Mark field data for deletion by invoking
-      // hook_field_storage_delete_field().
-      $module_handler->invoke($this->storage['module'], 'field_storage_delete_field', array($this));
+      \Drupal::entityManager()->getStorageController($this->entity_type)->handleFieldDelete($this);
 
       // Delete the configuration of this field and save the field configuration
       // in the key_value table so we can use it later during
@@ -528,30 +497,11 @@ public function getColumns() {
   /**
    * {@inheritdoc}
    */
-  public function getStorageDetails() {
-    if (!isset($this->storageDetails)) {
-      $module_handler = \Drupal::moduleHandler();
-
-      // Collect the storage details from the storage backend, and let other
-      // modules alter it. This invokes hook_field_storage_details() and
-      // hook_field_storage_details_alter().
-      $details = (array) $module_handler->invoke($this->storage['module'], 'field_storage_details', array($this));
-      $module_handler->alter('field_storage_details', $details, $this);
-
-      $this->storageDetails = $details;
-    }
-
-    return $this->storageDetails;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
   public function getBundles() {
     if (empty($this->deleted)) {
       $map = field_info_field_map();
-      if (isset($map[$this->id]['bundles'])) {
-        return $map[$this->id]['bundles'];
+      if (isset($map[$this->name]['bundles'])) {
+        return $map[$this->name]['bundles'];
       }
     }
     return array();
@@ -561,7 +511,7 @@ public function getBundles() {
    * {@inheritdoc}
    */
   public function getFieldName() {
-    return $this->id;
+    return $this->name;
   }
 
   /**
@@ -575,10 +525,6 @@ public function getFieldType() {
    * {@inheritdoc}
    */
   public function getFieldSettings() {
-    // @todo field_info_field_types() calls _field_info_collate_types() which
-    //   maintains its own static cache. However, do some CPU and memory
-    //   profiling to see if it's worth statically caching $field_type_info, or
-    //   the default field and instance settings, within $this.
     $field_type_info = field_info_field_types($this->type);
 
     $settings = $field_type_info['instance_settings'] + $this->settings + $field_type_info['settings'];
@@ -664,7 +610,7 @@ public function &offsetGet($offset) {
         return $this->uuid;
 
       case 'field_name':
-        return $this->id;
+        return $this->name;
 
       case 'columns':
         $this->getSchema();
@@ -677,10 +623,6 @@ public function &offsetGet($offset) {
       case 'bundles':
         $bundles = $this->getBundles();
         return $bundles;
-
-      case 'storage_details':
-        $this->getStorageDetails();
-        return $this->storageDetails;
     }
 
     return $this->{$offset};
@@ -747,7 +689,7 @@ public function hasData() {
       $query = $factory->get($entity_type);
       $group = $query->orConditionGroup();
       foreach ($columns as $column) {
-        $group->exists($this->id() . '.' . $column);
+        $group->exists($this->name . '.' . $column);
       }
       $result = $query
         ->condition($group)
@@ -762,4 +704,5 @@ public function hasData() {
 
     return FALSE;
   }
+
 }
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 cbfb636..2566110 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
@@ -7,6 +7,7 @@
 
 namespace Drupal\field\Plugin\Core\Entity;
 
+use Drupal\Component\Utility\String;
 use Drupal\Core\Entity\Annotation\EntityType;
 use Drupal\Core\Annotation\Translation;
 use Drupal\Core\Config\Entity\ConfigEntityBase;
@@ -235,7 +236,7 @@ public function __construct(array $values, $entity_type = 'field_instance') {
     // Accept incoming 'field_name' instead of 'field_uuid', for easier DX on
     // creation of new instances.
     if (isset($values['field_name']) && !isset($values['field_uuid'])) {
-      $field = field_info_field($values['field_name']);
+      $field = field_info_field($values['entity_type'], $values['field_name']);
       if (!$field) {
         throw new FieldException(format_string('Attempt to create an instance of unknown, disabled, or deleted field @field_id', array('@field_id' => $values['field_name'])));
       }
@@ -265,17 +266,14 @@ public function __construct(array $values, $entity_type = 'field_instance') {
     unset($values['field_type']);
 
     // Check required properties.
-    if (empty($values['entity_type'])) {
-      throw new FieldException(format_string('Attempt to create an instance of field @field_id without an entity type.', array('@field_id' => $this->field->id)));
-    }
     if (empty($values['bundle'])) {
       throw new FieldException(format_string('Attempt to create an instance of field @field_id without a bundle.', array('@field_id' => $this->field->id)));
     }
 
-    // 'Label' defaults to the field ID (mostly useful for field instances
+    // 'Label' defaults to the field name (mostly useful for field instances
     // created in tests).
     $values += array(
-      'label' => $this->field->id,
+      'label' => $this->field->name,
     );
     parent::__construct($values, $entity_type);
   }
@@ -284,7 +282,7 @@ public function __construct(array $values, $entity_type = 'field_instance') {
    * {@inheritdoc}
    */
   public function id() {
-    return $this->entity_type . '.' . $this->bundle . '.' . $this->field->id;
+    return $this->entity_type . '.' . $this->bundle . '.' . $this->field->name;
   }
 
   /**
@@ -352,20 +350,14 @@ public function save() {
    *   In case of failures at the configuration storage level.
    */
   protected function saveNew() {
-    $module_handler = \Drupal::moduleHandler();
     $instance_controller = \Drupal::entityManager()->getStorageController($this->entityType);
 
-    // Check that the field can be attached to this entity type.
-    if (!empty($this->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_id on forbidden entity type @entity_type.', array('@field_id' => $this->field->id, '@entity_type' => $this->entity_type)));
-    }
-
     // Assign the ID.
     $this->id = $this->id();
 
     // Ensure the field instance is unique within the bundle.
     if ($prior_instance = $instance_controller->load($this->id)) {
-      throw new FieldException(format_string('Attempt to create an instance of field @field_id on bundle @bundle that already has an instance of that field.', array('@field_id' => $this->field->id, '@bundle' => $this->bundle)));
+      throw new FieldException(format_string('Attempt to create an instance of field %name on bundle @bundle that already has an instance of that field.', array('%name' => $this->field->name, '@bundle' => $this->bundle)));
     }
 
     // Set the field UUID.
@@ -394,7 +386,6 @@ protected function saveNew() {
    *   In case of failures at the configuration storage level.
    */
   protected function saveUpdated() {
-    $module_handler = \Drupal::moduleHandler();
     $instance_controller = \Drupal::entityManager()->getStorageController($this->entityType);
 
     $original = $instance_controller->loadUnchanged($this->getOriginalID());
@@ -414,6 +405,9 @@ protected function saveUpdated() {
     // Ensure default values are present.
     $this->prepareSave();
 
+    // Notify the entity storage controller.
+    \Drupal::entityManager()->getStorageController($this->entity_type)->handleInstanceUpdate($this, $original);
+
     // Save the configuration.
     $result = parent::save();
     field_cache_clear();
@@ -441,7 +435,6 @@ protected function prepareSave() {
    */
   public function delete($field_cleanup = TRUE) {
     if (!$this->deleted) {
-      $module_handler = \Drupal::moduleHandler();
       $state = \Drupal::state();
 
       // Delete the configuration of this instance and save the configuration
@@ -455,16 +448,15 @@ public function delete($field_cleanup = TRUE) {
 
       parent::delete();
 
+      // Notify the entity storage controller.
+      \Drupal::entityManager()->getStorageController($this->entity_type)->handleInstanceDelete($this);
+
       // Clear the cache.
       field_cache_clear();
 
-      // Mark instance data for deletion by invoking
-      // hook_field_storage_delete_instance().
-      $module_handler->invoke($this->field->storage['module'], 'field_storage_delete_instance', array($this));
-
       // Remove the instance from the entity form displays.
       if ($form_display = entity_load('entity_form_display', $this->entity_type . '.' . $this->bundle . '.default')) {
-        $form_display->removeComponent($this->field->id())->save();
+        $form_display->removeComponent($this->field->name)->save();
       }
 
       // Remove the instance from the entity displays.
@@ -474,7 +466,7 @@ public function delete($field_cleanup = TRUE) {
         $ids[] = $this->entity_type . '.' . $this->bundle . '.' . $view_mode;
       }
       foreach (entity_load_multiple('entity_display', $ids) as $display) {
-        $display->removeComponent($this->field->id())->save();
+        $display->removeComponent($this->field->name)->save();
       }
 
       // Delete the field itself if we just deleted its last instance.
@@ -495,7 +487,7 @@ public function getField() {
    * {@inheritdoc}
    */
   public function getFieldName() {
-    return $this->field->id;
+    return $this->field->name;
   }
 
   /**
@@ -589,7 +581,7 @@ public function &offsetGet($offset) {
       return $this->field_uuid;
     }
     if ($offset == 'field_name') {
-      return $this->field->id;
+      return $this->field->name;
     }
     return $this->{$offset};
   }
diff --git a/core/modules/field/lib/Drupal/field/Plugin/views/argument/FieldList.php b/core/modules/field/lib/Drupal/field/Plugin/views/argument/FieldList.php
index d6ddcac..75b7252 100644
--- a/core/modules/field/lib/Drupal/field/Plugin/views/argument/FieldList.php
+++ b/core/modules/field/lib/Drupal/field/Plugin/views/argument/FieldList.php
@@ -35,7 +35,7 @@ class FieldList extends Numeric {
   public function init(ViewExecutable $view, DisplayPluginBase $display, array &$options = NULL) {
     parent::init($view, $display, $options);
 
-    $field = field_info_field($this->definition['field_name']);
+    $field = field_info_field($this->definition['entity_type'], $this->definition['field_name']);
     $this->allowed_values = options_allowed_values($field);
   }
 
diff --git a/core/modules/field/lib/Drupal/field/Plugin/views/argument/ListString.php b/core/modules/field/lib/Drupal/field/Plugin/views/argument/ListString.php
index 0c34d1b..83e24d9 100644
--- a/core/modules/field/lib/Drupal/field/Plugin/views/argument/ListString.php
+++ b/core/modules/field/lib/Drupal/field/Plugin/views/argument/ListString.php
@@ -35,7 +35,7 @@ class ListString extends String {
   public function init(ViewExecutable $view, DisplayPluginBase $display, array &$options = NULL) {
     parent::init($view, $display, $options);
 
-    $field = field_info_field($this->definition['field_name']);
+    $field = field_info_field($this->definition['entity_type'], $this->definition['field_name']);
     $this->allowed_values = options_allowed_values($field);
   }
 
diff --git a/core/modules/field/lib/Drupal/field/Plugin/views/field/Field.php b/core/modules/field/lib/Drupal/field/Plugin/views/field/Field.php
index 2346271..4c7e477 100644
--- a/core/modules/field/lib/Drupal/field/Plugin/views/field/Field.php
+++ b/core/modules/field/lib/Drupal/field/Plugin/views/field/Field.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\field\Plugin\views\field;
 
+use Drupal\Core\Entity\DatabaseStorageController;
 use Drupal\Core\Language\Language;
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\field\Plugin\Type\Formatter\FormatterPluginManager;
@@ -111,7 +112,7 @@ public static function create(ContainerInterface $container, array $configuratio
   public function init(ViewExecutable $view, DisplayPluginBase $display, array &$options = NULL) {
     parent::init($view, $display, $options);
 
-    $this->field_info = $field = field_info_field($this->definition['field_name']);
+    $this->field_info = $field = field_info_field($this->definition['entity_type'], $this->definition['field_name']);
     $this->multiple = FALSE;
     $this->limit_values = FALSE;
 
@@ -286,7 +287,8 @@ public function clickSort($order) {
     }
 
     $this->ensureMyTable();
-    $column = _field_sql_storage_columnname($this->definition['field_name'], $this->options['click_sort_column']);
+    $field = field_info_field($this->definition['entity_type'], $this->definition['field_name']);
+    $column = DatabaseStorageController::_fieldColumnName($field, $this->options['click_sort_column']);
     if (!isset($this->aliases[$column])) {
       // Column is not in query; add a sort on it (without adding the column).
       $this->aliases[$column] = $this->tableAlias . '.' . $column;
@@ -298,7 +300,7 @@ protected function defineOptions() {
     $options = parent::defineOptions();
 
     // defineOptions runs before init/construct, so no $this->field_info
-    $field = field_info_field($this->definition['field_name']);
+    $field = field_info_field($this->definition['entity_type'], $this->definition['field_name']);
     $field_type = field_info_field_types($field['type']);
     $column_names = array_keys($field['columns']);
     $default_column = '';
diff --git a/core/modules/field/lib/Drupal/field/Plugin/views/filter/FieldList.php b/core/modules/field/lib/Drupal/field/Plugin/views/filter/FieldList.php
index cfd2f6c..2b1d57c 100644
--- a/core/modules/field/lib/Drupal/field/Plugin/views/filter/FieldList.php
+++ b/core/modules/field/lib/Drupal/field/Plugin/views/filter/FieldList.php
@@ -20,7 +20,7 @@
 class FieldList extends ManyToOne {
 
   public function getValueOptions() {
-    $field = field_info_field($this->definition['field_name']);
+    $field = field_info_field($this->definition['entity_type'], $this->definition['field_name']);
     $this->value_options = list_allowed_values($field);
   }
 
diff --git a/core/modules/field/lib/Drupal/field/Plugin/views/relationship/EntityReverse.php b/core/modules/field/lib/Drupal/field/Plugin/views/relationship/EntityReverse.php
index 481105f..3103945 100644
--- a/core/modules/field/lib/Drupal/field/Plugin/views/relationship/EntityReverse.php
+++ b/core/modules/field/lib/Drupal/field/Plugin/views/relationship/EntityReverse.php
@@ -28,7 +28,7 @@ class EntityReverse extends RelationshipPluginBase  {
   public function init(ViewExecutable $view, DisplayPluginBase $display, array &$options = NULL) {
     parent::init($view, $display, $options);
 
-    $this->field_info = field_info_field($this->definition['field_name']);
+    $this->field_info = field_info_field($this->definition['entity_type'], $this->definition['field_name']);
   }
 
   /**
diff --git a/core/modules/field/lib/Drupal/field/Tests/ActiveTest.php b/core/modules/field/lib/Drupal/field/Tests/ActiveTest.php
index c74d426..fc10c26 100644
--- a/core/modules/field/lib/Drupal/field/Tests/ActiveTest.php
+++ b/core/modules/field/lib/Drupal/field/Tests/ActiveTest.php
@@ -14,7 +14,7 @@ class ActiveTest extends FieldTestBase {
    *
    * @var array
    */
-  public static $modules = array('field_test');
+  public static $modules = array('field_test', 'entity_test');
 
   public static function getInfo() {
     return array(
@@ -29,37 +29,14 @@ public static function getInfo() {
    */
   function testActive() {
     $field_definition = array(
-      'field_name' => 'field_1',
+      'name' => 'field_1',
+      'entity_type' => 'entity_test',
       'type' => 'test_field',
-      // For this test, we need a storage backend provided by a different
-      // module than field_test.module.
-      'storage' => array(
-        'type' => 'field_sql_storage',
-      ),
     );
     entity_create('field_entity', $field_definition)->save();
 
-    // Test disabling and enabling:
-    // - the field type module,
-    // - the storage module,
-    // - both.
-    $this->_testActiveHelper($field_definition, array('field_test'));
-    $this->_testActiveHelper($field_definition, array('field_sql_storage'));
-    $this->_testActiveHelper($field_definition, array('field_test', 'field_sql_storage'));
-  }
-
-  /**
-   * Helper function for testActive().
-   *
-   * Test dependency between a field and a set of modules.
-   *
-   * @param $field_definition
-   *   A field definition.
-   * @param $modules
-   *   An aray of module names. The field will be tested to be inactive as long
-   *   as any of those modules is disabled.
-   */
-  function _testActiveHelper($field_definition, $modules) {
+    // Test disabling and enabling the field type module,
+    $modules = array('field_test');
     $field_name = $field_definition['field_name'];
 
     // Read the field.
diff --git a/core/modules/field/lib/Drupal/field/Tests/BulkDeleteTest.php b/core/modules/field/lib/Drupal/field/Tests/BulkDeleteTest.php
index 9637826..51b89f4 100644
--- a/core/modules/field/lib/Drupal/field/Tests/BulkDeleteTest.php
+++ b/core/modules/field/lib/Drupal/field/Tests/BulkDeleteTest.php
@@ -7,10 +7,10 @@
 
 namespace Drupal\field\Tests;
 
-use Drupal\field\Plugin\Core\Entity\FieldInstance;
+use Drupal\Core\Entity\DatabaseStorageController;
 use Drupal\Core\Entity\EntityInterface;
+use Drupal\field\FieldInterface;
 
-use Drupal\Core\Language\Language;
 
 /**
  * Unit test class for field bulk delete and batch purge functionality.
@@ -50,7 +50,7 @@ class BulkDeleteTest extends FieldUnitTestBase {
    *
    * @var array
    */
-  protected $entity_type = 'test_entity';
+  protected $entity_type = 'entity_test';
 
   public static function getInfo() {
     return array(
@@ -114,14 +114,16 @@ function setUp() {
 
     // Create two fields.
     $field = entity_create('field_entity', array(
-      'field_name' => 'bf_1',
+      'name' => 'bf_1',
+      'entity_type' => $this->entity_type,
       'type' => 'test_field',
       'cardinality' => 1
     ));
     $field->save();
     $this->fields[] = $field;
     $field = entity_create('field_entity', array(
-      'field_name' => 'bf_2',
+      'name' => 'bf_2',
+      'entity_type' => $this->entity_type,
       'type' => 'test_field',
       'cardinality' => 4
     ));
@@ -130,11 +132,10 @@ function setUp() {
 
     // For each bundle, create an instance of each field, and 10
     // entities with values for each field.
-    $this->entity_type = 'entity_test';
     foreach ($this->bundles as $bundle) {
       foreach ($this->fields as $field) {
         entity_create('field_instance', array(
-          'field_name' => $field->id(),
+          'field_name' => $field->getFieldName(),
           'entity_type' => $this->entity_type,
           'bundle' => $bundle,
         ))->save();
@@ -165,7 +166,7 @@ function setUp() {
   function testDeleteFieldInstance() {
     $bundle = reset($this->bundles);
     $field = reset($this->fields);
-    $field_name = $field->id();
+    $field_name = $field->getFieldName();
     $factory = \Drupal::service('entity.query');
 
     // There are 10 entities of this bundle.
@@ -175,7 +176,7 @@ function testDeleteFieldInstance() {
     $this->assertEqual(count($found), 10, 'Correct number of entities found before deleting');
 
     // Delete the instance.
-    $instance = field_info_instance($this->entity_type, $field->id(), $bundle);
+    $instance = field_info_instance($this->entity_type, $field->getFieldName(), $bundle);
     $instance->delete();
 
     // The instance still exists, deleted.
@@ -198,19 +199,25 @@ function testDeleteFieldInstance() {
       ->condition("$field_name.deleted", 1)
       ->sort('id')
       ->execute();
-    $ids = (object) array(
-      'entity_type' => 'entity_test',
-      'bundle' => $bundle,
-    );
-    $entities = array();
-    foreach ($found as $entity_id) {
-      $ids->entity_id = $entity_id;
-      $entities[$entity_id] = _field_create_entity_from_ids($ids);
-    }
-    field_attach_load($this->entity_type, $entities, FIELD_LOAD_CURRENT, array('instance' => $instance));
     $this->assertEqual(count($found), 10, 'Correct number of entities found after deleting');
-    foreach ($entities as $id => $entity) {
-      $this->assertEqual($this->entities[$id]->{$field->id()}->value, $entity->{$field->id()}[Language::LANGCODE_NOT_SPECIFIED][0]['value'], "Entity $id with deleted data loaded correctly");
+    $this->assertFalse(array_diff($found, array_keys($this->entities)));
+    $this->checkFieldTableContents($field);
+  }
+
+  /**
+   * Test that the actual stored content didn't change during delete.
+   *
+   * @param FieldInterface $field
+   */
+  protected function checkFieldTableContents(FieldInterface $field) {
+    $schema = DatabaseStorageController::_fieldSqlSchema($field);
+    $table = DatabaseStorageController::_fieldTableName($field);
+    $column = DatabaseStorageController::_fieldColumnName($field, 'value');
+    $result = db_select($table, 't')
+      ->fields('t', array_keys($schema[$table]['fields']))
+      ->execute();
+    foreach ($result as $row) {
+      $this->assertEqual($this->entities[$row->entity_id]->{$field->getFieldName()}->value, $row->$column);
     }
   }
 
@@ -226,7 +233,7 @@ function testPurgeInstance() {
     $field = reset($this->fields);
 
     // Delete the instance.
-    $instance = field_info_instance($this->entity_type, $field->id(), $bundle);
+    $instance = field_info_instance($this->entity_type, $field->getFieldName(), $bundle);
     $instance->delete();
 
     // No field hooks were called.
@@ -241,19 +248,18 @@ function testPurgeInstance() {
       // There are $count deleted entities left.
       $found = \Drupal::entityQuery('entity_test')
         ->condition('type', $bundle)
-        ->condition($field->id() . '.deleted', 1)
+        ->condition($field->getFieldName() . '.deleted', 1)
         ->execute();
       $this->assertEqual(count($found), $count, 'Correct number of entities found after purging 2');
     }
 
     // Check hooks invocations.
-    // hook_field_load() and hook_field_delete() should have been called once
-    // for each entity in the bundle.
+    // hook_field_delete() should have been called once for each entity in the
+    // bundle.
     $actual_hooks = field_test_memorize();
     $hooks = array();
     $entities = $this->entities_by_bundles[$bundle];
     foreach ($entities as $id => $entity) {
-      $hooks['field_test_field_load'][] = array($id => $entity);
       $hooks['field_test_field_delete'][] = $entity;
     }
     $this->checkHooksInvocations($hooks, $actual_hooks);
@@ -286,7 +292,7 @@ function testPurgeField() {
 
     // Delete the first instance.
     $bundle = reset($this->bundles);
-    $instance = field_info_instance($this->entity_type, $field->id(), $bundle);
+    $instance = field_info_instance($this->entity_type, $field->getFieldName(), $bundle);
     $instance->delete();
 
     // Assert that hook_field_delete() was not called yet.
@@ -297,13 +303,12 @@ function testPurgeField() {
     field_purge_batch(10);
 
     // Check hooks invocations.
-    // hook_field_load() and hook_field_delete() should have been called once
-    // for each entity in the bundle.
+    // hook_field_delete() should have been called once for each entity in the
+    // bundle.
     $actual_hooks = field_test_memorize();
     $hooks = array();
     $entities = $this->entities_by_bundles[$bundle];
     foreach ($entities as $id => $entity) {
-      $hooks['field_test_field_load'][] = array($id => $entity);
       $hooks['field_test_field_delete'][] = $entity;
     }
     $this->checkHooksInvocations($hooks, $actual_hooks);
@@ -317,7 +322,7 @@ function testPurgeField() {
 
     // Delete the second instance.
     $bundle = next($this->bundles);
-    $instance = field_info_instance($this->entity_type, $field->id(), $bundle);
+    $instance = field_info_instance($this->entity_type, $field->getFieldName(), $bundle);
     $instance->delete();
 
     // Assert that hook_field_delete() was not called yet.
@@ -332,7 +337,6 @@ function testPurgeField() {
     $hooks = array();
     $entities = $this->entities_by_bundles[$bundle];
     foreach ($entities as $id => $entity) {
-      $hooks['field_test_field_load'][] = array($id => $entity);
       $hooks['field_test_field_delete'][] = $entity;
     }
     $this->checkHooksInvocations($hooks, $actual_hooks);
diff --git a/core/modules/field/lib/Drupal/field/Tests/CrudTest.php b/core/modules/field/lib/Drupal/field/Tests/CrudTest.php
index b7b7d58..9fef78b 100644
--- a/core/modules/field/lib/Drupal/field/Tests/CrudTest.php
+++ b/core/modules/field/lib/Drupal/field/Tests/CrudTest.php
@@ -37,7 +37,8 @@ public static function getInfo() {
    */
   function testCreateField() {
     $field_definition = array(
-      'field_name' => 'field_2',
+      'name' => 'field_2',
+      'entity_type' => 'entity_test',
       'type' => 'test_field',
     );
     field_test_memorize();
@@ -50,7 +51,7 @@ function testCreateField() {
     // Read the configuration. Check against raw configuration data rather than
     // the loaded ConfigEntity, to be sure we check that the defaults are
     // applied on write.
-    $field_config = \Drupal::config('field.field.' . $field->id())->get();
+    $field_config = \Drupal::config('field.field.' . $field->getFieldName())->get();
 
     // Ensure that basic properties are preserved.
     $this->assertEqual($field_config['id'], $field_definition['field_name'], 'The field name is properly saved.');
@@ -63,9 +64,6 @@ function testCreateField() {
     $field_type = field_info_field_types($field_definition['type']);
     $this->assertEqual($field_config['settings'], $field_type['settings'], 'Default field settings have been written.');
 
-    // Ensure that default storage was set.
-    $this->assertEqual($field_config['storage']['type'], config('field.settings')->get('default_storage'), 'The field type is properly saved.');
-
     // Guarantee that the name is unique.
     try {
       entity_create('field_entity', $field_definition)->save();
@@ -78,7 +76,8 @@ function testCreateField() {
     // Check that field type is required.
     try {
       $field_definition = array(
-        'field_name' => 'field_1',
+        'name' => 'field_1',
+        'entity_type' => 'entity_type',
       );
       entity_create('field_entity', $field_definition)->save();
       $this->fail(t('Cannot create a field with no type.'));
@@ -90,7 +89,8 @@ function testCreateField() {
     // Check that field name is required.
     try {
       $field_definition = array(
-        'type' => 'test_field'
+        'type' => 'test_field',
+        'entity_type' => 'entity_test',
       );
       entity_create('field_entity', $field_definition)->save();
       $this->fail(t('Cannot create an unnamed field.'));
@@ -98,11 +98,24 @@ function testCreateField() {
     catch (FieldException $e) {
       $this->pass(t('Cannot create an unnamed field.'));
     }
+    // Check that entity type is required.
+    try {
+      $field_definition = array(
+        'name' => 'test_field',
+        'type' => 'test_field'
+      );
+      entity_create('field_entity', $field_definition)->save();
+      $this->fail('Cannot create a field without an entity type.');
+    }
+    catch (FieldException $e) {
+      $this->pass('Cannot create a field without an entity type.');
+    }
 
     // Check that field name must start with a letter or _.
     try {
       $field_definition = array(
-        'field_name' => '2field_2',
+        'name' => '2field_2',
+        'entity_type' => 'entity_test',
         'type' => 'test_field',
       );
       entity_create('field_entity', $field_definition)->save();
@@ -115,7 +128,8 @@ function testCreateField() {
     // Check that field name must only contain lowercase alphanumeric or _.
     try {
       $field_definition = array(
-        'field_name' => 'field#_3',
+        'name' => 'field#_3',
+        'entity_type' => 'entity_test',
         'type' => 'test_field',
       );
       entity_create('field_entity', $field_definition)->save();
@@ -128,7 +142,8 @@ function testCreateField() {
     // Check that field name cannot be longer than 32 characters long.
     try {
       $field_definition = array(
-        'field_name' => '_12345678901234567890123456789012',
+        'name' => '_12345678901234567890123456789012',
+        'entity_type' => 'entity_test',
         'type' => 'test_field',
       );
       entity_create('field_entity', $field_definition)->save();
@@ -143,7 +158,8 @@ function testCreateField() {
     try {
       $field_definition = array(
         'type' => 'test_field',
-        'field_name' => 'id',
+        'name' => 'id',
+        'entity_type' => 'entity_test',
       );
       entity_create('field_entity', $field_definition)->save();
       $this->fail(t('Cannot create a field bearing the name of an entity key.'));
@@ -154,36 +170,12 @@ function testCreateField() {
   }
 
   /**
-   * Test failure to create a field.
-   */
-  function testCreateFieldFail() {
-    $field_name = 'duplicate';
-    $field_definition = array('field_name' => $field_name, 'type' => 'test_field', 'storage' => array('type' => 'field_test_storage_failure'));
-    $field = entity_load('field_entity', $field_name);
-
-    // The field does not exist.
-    $this->assertFalse($field, 'The field does not exist.');
-
-    // Try to create the field.
-    try {
-      entity_create('field_entity', $field_definition)->save();
-      $this->assertTrue(FALSE, 'Field creation (correctly) fails.');
-    }
-    catch (\Exception $e) {
-      $this->assertTrue(TRUE, 'Field creation (correctly) fails.');
-    }
-
-    // The field does not exist.
-    $field = entity_load('field_entity', $field_name);
-    $this->assertFalse($field, 'The field does not exist.');
-  }
-
-  /**
    * Tests reading a single field definition.
    */
   function testReadField() {
     $field_definition = array(
-      'field_name' => 'field_1',
+      'name' => 'field_1',
+      'entity_type' => 'entity_test',
       'type' => 'test_field',
     );
     entity_create('field_entity', $field_definition)->save();
@@ -198,7 +190,8 @@ function testReadField() {
    */
   function testReadFields() {
     $field_definition = array(
-      'field_name' => 'field_1',
+      'name' => 'field_1',
+      'entity_type' => 'entity_test',
       'type' => 'test_field',
     );
     entity_create('field_entity', $field_definition)->save();
@@ -228,7 +221,8 @@ function testReadFields() {
   function testFieldIndexes() {
     // Check that indexes specified by the field type are used by default.
     $field_definition = array(
-      'field_name' => 'field_1',
+      'name' => 'field_1',
+      'entity_type' => 'entity_test',
       'type' => 'test_field',
     );
     entity_create('field_entity', $field_definition)->save();
@@ -240,7 +234,8 @@ function testFieldIndexes() {
     // Check that indexes specified by the field definition override the field
     // type indexes.
     $field_definition = array(
-      'field_name' => 'field_2',
+      'name' => 'field_2',
+      'entity_type' => 'entity_test',
       'type' => 'test_field',
       'indexes' => array(
         'value' => array(),
@@ -255,7 +250,8 @@ function testFieldIndexes() {
     // Check that indexes specified by the field definition add to the field
     // type indexes.
     $field_definition = array(
-      'field_name' => 'field_3',
+      'name' => 'field_3',
+      'entity_type' => 'entity_test',
       'type' => 'test_field',
       'indexes' => array(
         'value_2' => array('value'),
@@ -275,15 +271,22 @@ function testDeleteField() {
     // TODO: Also test deletion of the data stored in the field ?
 
     // Create two fields (so we can test that only one is deleted).
-    $this->field = array('field_name' => 'field_1', 'type' => 'test_field');
+    $this->field = array(
+      'name' => 'field_1',
+      'type' => 'test_field',
+      'entity_type' => 'entity_test',
+    );
     entity_create('field_entity', $this->field)->save();
-    $this->another_field = array('field_name' => 'field_2', 'type' => 'test_field');
+    $this->another_field = array(
+      'name' => 'field_2',
+      'type' => 'test_field',
+      'entity_type' => 'entity_test',
+    );
     entity_create('field_entity', $this->another_field)->save();
 
     // Create instances for each.
     $this->instance_definition = array(
       'field_name' => $this->field['field_name'],
-      'entity_type' => 'entity_test',
       'bundle' => 'entity_test',
     );
     entity_create('field_instance', $this->instance_definition)->save();
@@ -294,7 +297,7 @@ function testDeleteField() {
     // Test that the first field is not deleted, and then delete it.
     $field = field_read_field($this->field['field_name'], array('include_deleted' => TRUE));
     $this->assertTrue(!empty($field) && empty($field['deleted']), 'A new field is not marked for deletion.');
-    field_info_field($this->field['field_name'])->delete();
+    field_info_field('entity_test', $this->field['field_name'])->delete();
 
     // Make sure that the field is marked as deleted when it is specifically
     // loaded.
@@ -330,15 +333,12 @@ function testDeleteField() {
     $this->assertTrue(!empty($instance) && empty($instance['deleted']), 'A new instance for a previously used field name is created.');
 
     // Save an entity with data for the field
-    $entity = entity_create('entity_test', array('id' => 0, 'revision_id' => 0));
-    $langcode = Language::LANGCODE_NOT_SPECIFIED;
+    $entity = entity_create('entity_test', array());
     $values[0]['value'] = mt_rand(1, 127);
     $entity->{$field['field_name']}->value = $values[0]['value'];
-    field_attach_insert($entity);
+    $entity = $this->entitySaveReload($entity);
 
     // Verify the field is present on load
-    $entity = entity_create('entity_test', array('id' => 0, 'revision_id' => 0));
-    field_attach_load('entity_test', array(0 => $entity));
     $this->assertIdentical(count($entity->{$field['field_name']}), count($values), "Data in previously deleted field saves and loads correctly");
     foreach ($values as $delta => $value) {
       $this->assertEqual($entity->{$field['field_name']}[$delta]->value, $values[$delta]['value'], "Data in previously deleted field saves and loads correctly");
@@ -346,7 +346,11 @@ function testDeleteField() {
   }
 
   function testUpdateFieldType() {
-    $field_definition = array('field_name' => 'field_type', 'type' => 'number_decimal');
+    $field_definition = array(
+      'name' => 'field_type',
+      'entity_type' => 'entity_test',
+      'type' => 'number_decimal',
+    );
     $field = entity_create('field_entity', $field_definition);
     $field->save();
 
@@ -369,7 +373,8 @@ function testUpdateField() {
     // systems, it makes a good test case.
     $cardinality = 4;
     $field = entity_create('field_entity', array(
-      'field_name' => 'field_update',
+      'name' => 'field_update',
+      'entity_type' => 'entity_test',
       'type' => 'test_field',
       'cardinality' => $cardinality,
     ));
@@ -382,22 +387,18 @@ function testUpdateField() {
     $instance->save();
 
     do {
-      // We need a unique ID for our entity. $cardinality will do.
-      $id = $cardinality;
-      $entity = entity_create('entity_test', array('id' => $id, 'revision_id' => $id));
+      $entity = entity_create('entity_test', array());
       // Fill in the entity with more values than $cardinality.
       for ($i = 0; $i < 20; $i++) {
-        $entity->field_update[$i]->value = $i;
+        // We can not use $i here because 0 values are filtered out.
+        $entity->field_update[$i]->value = $i + 1;
       }
-      // Save the entity.
-      field_attach_insert($entity);
       // Load back and assert there are $cardinality number of values.
-      $entity = entity_create('entity_test', array('id' => $id, 'revision_id' => $id));
-      field_attach_load('entity_test', array($id => $entity));
-      $this->assertEqual(count($entity->field_update), $field->cardinality, 'Cardinality is kept');
+      $entity = $this->entitySaveReload($entity);
+      $this->assertEqual(count($entity->field_update), $field->cardinality);
       // Now check the values themselves.
       for ($delta = 0; $delta < $cardinality; $delta++) {
-        $this->assertEqual($entity->field_update[$delta]->value, $delta, 'Value is kept');
+        $this->assertEqual($entity->field_update[$delta]->value, $delta + 1);
       }
       // Increase $cardinality and set the field cardinality to the new value.
       $field->cardinality = ++$cardinality;
@@ -410,7 +411,8 @@ function testUpdateField() {
    */
   function testUpdateFieldForbid() {
     $field = entity_create('field_entity', array(
-      'field_name' => 'forbidden',
+      'name' => 'forbidden',
+      'entit_type' => 'entity_test',
       'type' => 'test_field',
       'settings' => array(
         'changeable' => 0,
diff --git a/core/modules/field/lib/Drupal/field/Tests/DisplayApiTest.php b/core/modules/field/lib/Drupal/field/Tests/DisplayApiTest.php
index 70195d3..6ba2624 100644
--- a/core/modules/field/lib/Drupal/field/Tests/DisplayApiTest.php
+++ b/core/modules/field/lib/Drupal/field/Tests/DisplayApiTest.php
@@ -70,7 +70,8 @@ function setUp() {
     $this->cardinality = 4;
 
     $field = array(
-      'field_name' => $this->field_name,
+      'name' => $this->field_name,
+      'entity_type' => 'entity_test',
       'type' => 'test_field',
       'cardinality' => $this->cardinality,
     );
diff --git a/core/modules/field/lib/Drupal/field/Tests/FieldAccessTest.php b/core/modules/field/lib/Drupal/field/Tests/FieldAccessTest.php
index 58fb767..a355f75 100644
--- a/core/modules/field/lib/Drupal/field/Tests/FieldAccessTest.php
+++ b/core/modules/field/lib/Drupal/field/Tests/FieldAccessTest.php
@@ -52,7 +52,8 @@ function setUp() {
     $content_type = $content_type_info->type;
 
     $field = array(
-      'field_name' => 'test_view_field',
+      'name' => 'test_view_field',
+      'entity_type' => 'node',
       'type' => 'text',
     );
     entity_create('field_entity', $field)->save();
diff --git a/core/modules/field/lib/Drupal/field/Tests/FieldAttachOtherTest.php b/core/modules/field/lib/Drupal/field/Tests/FieldAttachOtherTest.php
index 4739d5f..f3f45e9 100644
--- a/core/modules/field/lib/Drupal/field/Tests/FieldAttachOtherTest.php
+++ b/core/modules/field/lib/Drupal/field/Tests/FieldAttachOtherTest.php
@@ -236,7 +236,7 @@ function testFieldAttachPrepareViewMultiple() {
    */
   function testFieldAttachCache() {
     // Initialize random values and a test entity.
-    $entity_init = entity_create('entity_test', array('id' => 1, 'revision_id' => 1, 'type' => $this->instance['bundle']));
+    $entity_init = entity_create('entity_test', array('type' => $this->instance['bundle']));
     $langcode = Language::LANGCODE_NOT_SPECIFIED;
     $values = $this->_generateTestFieldValues($this->field['cardinality']);
 
@@ -250,18 +250,12 @@ function testFieldAttachCache() {
     // Save, and check that no cache entry is present.
     $entity = clone($entity_init);
     $entity->{$this->field_name}->setValue($values);
-    field_attach_insert($entity);
-    $this->assertFalse(cache('field')->get($cid), 'Non-cached: no cache entry on insert');
-
-    // Load, and check that no cache entry is present.
-    $entity = clone($entity_init);
-    field_attach_load($entity_type, array($entity->id() => $entity));
-    $this->assertFalse(cache('field')->get($cid), 'Non-cached: no cache entry on load');
-
+    $entity = $this->entitySaveReload($entity);
+    $cid = "field:$entity_type:" . $entity->id();
+    $this->assertFalse(cache('field')->get($cid), 'Non-cached: no cache entry on insert and load');
 
     // Cacheable entity type.
     $entity_type = 'entity_test_cache';
-    $cid = "field:$entity_type:" . $entity_init->id();
     $instance_definition = $this->instance_definition;
     $instance_definition['entity_type'] = $entity_type;
     $instance_definition['bundle'] = $entity_type;
@@ -270,8 +264,6 @@ function testFieldAttachCache() {
     entity_info_cache_clear();
 
     $entity_init = entity_create($entity_type, array(
-      'id' => 1,
-      'revision_id' => 1,
       'type' => $entity_type,
     ));
 
@@ -281,56 +273,52 @@ function testFieldAttachCache() {
     // Save, and check that no cache entry is present.
     $entity = clone($entity_init);
     $entity->{$this->field_name} = $values;
-    field_attach_insert($entity);
+    $entity->save();
+    $cid = "field:$entity_type:" . $entity->id();
     $this->assertFalse(cache('field')->get($cid), 'Cached: no cache entry on insert');
 
-    // Load a single field, and check that no cache entry is present.
-    $entity = clone($entity_init);
-    $instance = field_info_instance($entity->entityType(), $this->field_name, $entity->bundle());
-    field_attach_load($entity_type, array($entity->id() => $entity), FIELD_LOAD_CURRENT, array('instance' => $instance));
-    $cache = cache('field')->get($cid);
-    $this->assertFalse($cache, 'Cached: no cache entry on loading a single field');
-
     // Load, and check that a cache entry is present with the expected values.
-    $entity = clone($entity_init);
-    field_attach_load($entity_type, array($entity->id() => $entity));
+    $controller = $this->container->get('plugin.manager.entity')->getStorageController($entity->entityType());
+    $controller->resetCache();
+    $controller->load($entity->id());
     $cache = cache('field')->get($cid);
     $this->assertEqual($cache->data[$this->field_name][$langcode], $values, 'Cached: correct cache entry on load');
 
     // Update with different values, and check that the cache entry is wiped.
     $values = $this->_generateTestFieldValues($this->field['cardinality']);
-    $entity = clone($entity_init);
+    $entity = entity_create($entity_type, array(
+      'type' => $entity_type,
+      'id' => $entity->id(),
+    ));
     $entity->{$this->field_name} = $values;
-    field_attach_update($entity);
+    $entity->save();
     $this->assertFalse(cache('field')->get($cid), 'Cached: no cache entry on update');
 
     // Load, and check that a cache entry is present with the expected values.
-    $entity = clone($entity_init);
-    field_attach_load($entity_type, array($entity->id() => $entity));
+    $controller->resetCache();
+    $controller->load($entity->id());
     $cache = cache('field')->get($cid);
     $this->assertEqual($cache->data[$this->field_name][$langcode], $values, 'Cached: correct cache entry on load');
 
     // Create a new revision, and check that the cache entry is wiped.
-    $entity_init = entity_create($entity_type, array(
-      'id' => 1,
-      'revision_id' => 2,
+    $entity = entity_create($entity_type, array(
       'type' => $entity_type,
+      'id' => $entity->id(),
     ));
     $values = $this->_generateTestFieldValues($this->field['cardinality']);
-    $entity = clone($entity_init);
     $entity->{$this->field_name} = $values;
-    field_attach_update($entity);
-    $cache = cache('field')->get($cid);
+    $entity->setNewRevision();
+    $entity->save();
     $this->assertFalse(cache('field')->get($cid), 'Cached: no cache entry on new revision creation');
 
     // Load, and check that a cache entry is present with the expected values.
-    $entity = clone($entity_init);
-    field_attach_load($entity_type, array($entity->id() => $entity));
+    $controller->resetCache();
+    $controller->load($entity->id());
     $cache = cache('field')->get($cid);
     $this->assertEqual($cache->data[$this->field_name][$langcode], $values, 'Cached: correct cache entry on load');
 
     // Delete, and check that the cache entry is wiped.
-    field_attach_delete($entity);
+    $entity->delete();
     $this->assertFalse(cache('field')->get($cid), 'Cached: no cache entry after delete');
   }
 
diff --git a/core/modules/field/lib/Drupal/field/Tests/FieldAttachStorageTest.php b/core/modules/field/lib/Drupal/field/Tests/FieldAttachStorageTest.php
index e5f28d0..bbc870b 100644
--- a/core/modules/field/lib/Drupal/field/Tests/FieldAttachStorageTest.php
+++ b/core/modules/field/lib/Drupal/field/Tests/FieldAttachStorageTest.php
@@ -62,26 +62,22 @@ function testFieldAttachSaveLoad() {
     // TODO : test empty values filtering and "compression" (store consecutive deltas).
     // Preparation: create three revisions and store them in $revision array.
     $values = array();
+    $entity = entity_create($entity_type, array());
     for ($revision_id = 0; $revision_id < 3; $revision_id++) {
-      $revision[$revision_id] = entity_create($entity_type, array('id' => 0, 'revision_id' => $revision_id));
       // Note: we try to insert one extra value.
-      $values[$revision_id] = $this->_generateTestFieldValues($this->field['cardinality'] + 1);
-      $current_revision = $revision_id;
-      // If this is the first revision do an insert.
-      if (!$revision_id) {
-        $revision[$revision_id]->{$this->field_name}->setValue($values[$revision_id]);
-        field_attach_insert($revision[$revision_id]);
-      }
-      else {
-        // Otherwise do an update.
-        $revision[$revision_id]->{$this->field_name}->setValue($values[$revision_id]);
-        field_attach_update($revision[$revision_id]);
-      }
+      $current_values = $this->_generateTestFieldValues($this->field['cardinality'] + 1);
+      $entity->{$this->field_name}->setValue($current_values);
+      $entity->setNewRevision();
+      $entity->save();
+      $entity_id = $entity->id();
+      $current_revision = $entity->getRevisionId();
+      $values[$current_revision] = $current_values;
     }
 
+    $storage_controller =  $this->container->get('plugin.manager.entity')->getStorageController($entity_type);
+    $storage_controller->resetCache();
+    $entity = $storage_controller->load($entity_id);
     // Confirm current revision loads the correct data.
-    $entity = entity_create($entity_type, array('id' => 0, 'revision_id' => 0));
-    field_attach_load($entity_type, array(0 => $entity));
     // Number of values per field loaded equals the field cardinality.
     $this->assertEqual(count($entity->{$this->field_name}), $this->field['cardinality'], 'Current revision: expected number of values');
     for ($delta = 0; $delta < $this->field['cardinality']; $delta++) {
@@ -92,9 +88,8 @@ function testFieldAttachSaveLoad() {
     }
 
     // Confirm each revision loads the correct data.
-    foreach (array_keys($revision) as $revision_id) {
-      $entity = entity_create($entity_type, array('id' => 0, 'revision_id' => $revision_id));
-      field_attach_load_revision($entity_type, array(0 => $entity));
+    foreach (array_keys($values) as $revision_id) {
+      $entity = $storage_controller->loadRevision($revision_id);
       // Number of values per field loaded equals the field cardinality.
       $this->assertEqual(count($entity->{$this->field_name}), $this->field['cardinality'], format_string('Revision %revision_id: expected number of values.', array('%revision_id' => $revision_id)));
       for ($delta = 0; $delta < $this->field['cardinality']; $delta++) {
@@ -130,7 +125,11 @@ function testFieldAttachLoadMultiple() {
     );
     for ($i = 1; $i <= 3; $i++) {
       $field_names[$i] = 'field_' . $i;
-      $field = entity_create('field_entity', array('field_name' => $field_names[$i], 'type' => 'test_field'));
+      $field = entity_create('field_entity', array(
+        'name' => $field_names[$i],
+        'entity_type' => $entity_type,
+        'type' => 'test_field',
+      ));
       $field->save();
       $field_ids[$i] = $field['uuid'];
       foreach ($field_bundles_map[$i] as $bundle) {
@@ -156,11 +155,14 @@ function testFieldAttachLoadMultiple() {
         $values[$index][$field_name] = mt_rand(1, 127);
         $entity->$field_name->setValue(array('value' => $values[$index][$field_name]));
       }
-      field_attach_insert($entity);
+      $entity->enforceIsnew();
+      $entity->save();
     }
 
     // Check that a single load correctly loads field values for both entities.
-    field_attach_load($entity_type, $entities);
+    $controller = $this->container->get('plugin.manager.entity')->getStorageController($entity->entityType());
+    $controller->resetCache();
+    $entities = $controller->loadMultiple();
     foreach ($entities as $index => $entity) {
       $instances = field_info_instances($entity_type, $bundles[$index]);
       foreach ($instances as $field_name => $instance) {
@@ -170,165 +172,48 @@ function testFieldAttachLoadMultiple() {
         $this->assertEqual($entity->{$field_name}->additional_key, 'additional_value', format_string('Entity %index: extra information was found', array('%index' => $index)));
       }
     }
-
-    // Check that the single-field load option works.
-    $entity = entity_create($entity_type, array('id' => 1, 'revision_id' => 1, 'type' => $bundles[1]));
-    $instance = field_info_instance($entity->entityType(), $field_names[1], $entity->bundle());
-    field_attach_load($entity_type, array(1 => $entity), FIELD_LOAD_CURRENT, array('instance' => $instance));
-    $this->assertEqual($entity->{$field_names[1]}->value, $values[1][$field_names[1]], format_string('Entity %index: expected value was found.', array('%index' => 1)));
-    $this->assertEqual($entity->{$field_names[1]}->additional_key, 'additional_value', format_string('Entity %index: extra information was found', array('%index' => 1)));
-    $this->assert(empty($entity->{$field_names[2]}->value), format_string('Entity %index: field %field_name is not loaded.', array('%index' => 2, '%field_name' => $field_names[2])));
-    $this->assert(!isset($entity->{$field_names[3]}), format_string('Entity %index: field %field_name is not loaded.', array('%index' => 3, '%field_name' => $field_names[3])));
-  }
-
-  /**
-   * Test saving and loading fields using different storage backends.
-   */
-  function testFieldAttachSaveLoadDifferentStorage() {
-    $entity_type = 'entity_test';
-
-    // Create two fields using different storage backends, and their instances.
-    $fields = array(
-      array(
-        'field_name' => 'field_1',
-        'type' => 'test_field',
-        'cardinality' => 4,
-        'storage' => array('type' => 'field_sql_storage')
-      ),
-      array(
-        'field_name' => 'field_2',
-        'type' => 'test_field',
-        'cardinality' => 4,
-        'storage' => array('type' => 'field_test_storage')
-      ),
-    );
-    foreach ($fields as $field) {
-      entity_create('field_entity', $field)->save();
-      $instance = array(
-        'field_name' => $field['field_name'],
-        'entity_type' => $entity_type,
-        'bundle' => $entity_type,
-      );
-      entity_create('field_instance', $instance)->save();
-    }
-
-    $entity_init = entity_create($entity_type, array('id' => 1, 'revision_id' => 1));
-
-    // Create entity and insert random values.
-    $entity = clone($entity_init);
-    $values = array();
-    foreach ($fields as $field) {
-      $values[$field['field_name']] = $this->_generateTestFieldValues($this->field['cardinality']);
-      $entity->{$field['field_name']} = $values[$field['field_name']];
-    }
-    field_attach_insert($entity);
-
-    // Check that values are loaded as expected.
-    $entity = clone($entity_init);
-    field_attach_load($entity_type, array($entity->id() => $entity));
-    foreach ($fields as $field) {
-      $this->assertEqual($values[$field['field_name']], $entity->{$field['field_name']}->getValue(), format_string('%storage storage: expected values were found.', array('%storage' => $field['storage']['type'])));
-    }
-  }
-
-  /**
-   * Test storage details alteration.
-   *
-   * @see field_test_storage_details_alter()
-   */
-  function testFieldStorageDetailsAlter() {
-    $field_name = 'field_test_change_my_details';
-    $field = entity_create('field_entity', array(
-      'field_name' => $field_name,
-      'type' => 'test_field',
-      'cardinality' => 4,
-      'storage' => array('type' => 'field_test_storage'),
-    ));
-    $field->save();
-    $instance = entity_create('field_instance', array(
-      'field_name' => $field_name,
-      'entity_type' => 'entity_test',
-      'bundle' => 'entity_test',
-    ));
-    $instance->save();
-
-    // The storage details are indexed by a storage engine type.
-    $this->assertTrue(array_key_exists('drupal_variables', $field['storage_details']), 'The storage type is Drupal variables.');
-
-    $details = $field['storage_details']['drupal_variables'];
-
-    // The field_test storage details are indexed by variable name. The details
-    // are altered, so moon and mars are correct for this test.
-    $this->assertTrue(array_key_exists('moon', $details[FIELD_LOAD_CURRENT]), 'Moon is available in the instance array.');
-    $this->assertTrue(array_key_exists('mars', $details[FIELD_LOAD_REVISION]), 'Mars is available in the instance array.');
-
-    // Test current and revision storage details together because the columns
-    // are the same.
-    foreach ($field['columns'] as $column_name => $attributes) {
-      $this->assertEqual($details[FIELD_LOAD_CURRENT]['moon'][$column_name], $column_name, format_string('Column name %value matches the definition in %bin.', array('%value' => $column_name, '%bin' => 'moon[FIELD_LOAD_CURRENT]')));
-      $this->assertEqual($details[FIELD_LOAD_REVISION]['mars'][$column_name], $column_name, format_string('Column name %value matches the definition in %bin.', array('%value' => $column_name, '%bin' => 'mars[FIELD_LOAD_REVISION]')));
-    }
   }
 
   /**
    * Tests insert and update with empty or NULL fields.
    */
   function testFieldAttachSaveEmptyData() {
-    $entity_type = 'entity_test_rev';
+    $entity_type = 'entity_test';
     $this->createFieldWithInstance('', $entity_type);
 
-    $entity_init = entity_create($entity_type, array('id' => 1, 'revision_id' => 1));
+    $entity_init = entity_create($entity_type, array('id' => 1));
 
     // Insert: Field is NULL.
-    field_cache_clear();
-    $entity = clone($entity_init);
+    $entity = clone $entity_init;
     $entity->{$this->field_name} = NULL;
-    field_attach_insert($entity);
-
-    $entity = clone($entity_init);
-    field_attach_load($entity_type, array($entity->id() => $entity));
+    $entity->enforceIsNew();
+    $entity = $this->entitySaveReload($entity);
     $this->assertTrue($entity->{$this->field_name}->isEmpty(), 'Insert: NULL field results in no value saved');
 
     // Add some real data.
-    field_cache_clear();
     $entity = clone($entity_init);
     $values = $this->_generateTestFieldValues(1);
     $entity->{$this->field_name} = $values;
-    field_attach_insert($entity);
-
-    $entity = clone($entity_init);
-    field_attach_load($entity_type, array($entity->id() => $entity));
+    $entity = $this->entitySaveReload($entity);
     $this->assertEqual($entity->{$this->field_name}->getValue(), $values, 'Field data saved');
 
     // Update: Field is NULL. Data should be wiped.
-    field_cache_clear();
     $entity = clone($entity_init);
     $entity->{$this->field_name} = NULL;
-    field_attach_update($entity);
-
-    $entity = clone($entity_init);
-    field_attach_load($entity_type, array($entity->id() => $entity));
+    $entity = $this->entitySaveReload($entity);
     $this->assertTrue($entity->{$this->field_name}->isEmpty(), 'Update: NULL field removes existing values');
 
     // Re-add some data.
-    field_cache_clear();
     $entity = clone($entity_init);
     $values = $this->_generateTestFieldValues(1);
     $entity->{$this->field_name} = $values;
-    field_attach_update($entity);
-
-    $entity = clone($entity_init);
-    field_attach_load($entity_type, array($entity->id() => $entity));
+    $entity = $this->entitySaveReload($entity);
     $this->assertEqual($entity->{$this->field_name}->getValue(), $values, 'Field data saved');
 
     // Update: Field is empty array. Data should be wiped.
-    field_cache_clear();
     $entity = clone($entity_init);
     $entity->{$this->field_name} = array();
-    field_attach_update($entity);
-
-    $entity = clone($entity_init);
-    field_attach_load($entity_type, array($entity->id() => $entity));
+    $entity = $this->entitySaveReload($entity);
     $this->assertTrue($entity->{$this->field_name}->isEmpty(), 'Update: empty array removes existing values');
   }
 
@@ -351,11 +236,8 @@ function testFieldAttachSaveEmptyDataDefaultValue() {
     // Insert: Field is NULL.
     $entity = clone($entity_init);
     $entity->getBCEntity()->{$this->field_name} = NULL;
-    field_attach_insert($entity);
-
-    $entity = clone($entity_init);
-    $entity->getBCEntity()->{$this->field_name} = array();
-    field_attach_load($entity_type, array($entity->id() => $entity));
+    $entity->enforceIsNew();
+    $entity = $this->entitySaveReload($entity);
     $this->assertTrue($entity->{$this->field_name}->isEmpty(), 'Insert: NULL field results in no value saved');
 
     // Verify that prepopulated field values are not overwritten by defaults.
@@ -370,53 +252,55 @@ function testFieldAttachSaveEmptyDataDefaultValue() {
   function testFieldAttachDelete() {
     $entity_type = 'entity_test_rev';
     $this->createFieldWithInstance('', $entity_type);
-    $rev[0] = entity_create($entity_type, array('id' => 0, 'revision_id' => 0, 'type' => $this->instance['bundle']));
+    $entity = entity_create($entity_type, array('type' => $this->instance['bundle']));
+    $vids = array();
 
     // Create revision 0
     $values = $this->_generateTestFieldValues($this->field['cardinality']);
-    $rev[0]->{$this->field_name} = $values;
-    field_attach_insert($rev[0]);
+    $entity->{$this->field_name} = $values;
+    $entity->save();
+    $vids[] = $entity->getRevisionId();
 
     // Create revision 1
-    $rev[1] = entity_create($entity_type, array('id' => 0, 'revision_id' => 1, 'type' => $this->instance['bundle']));
-    $rev[1]->{$this->field_name} = $values;
-    field_attach_update($rev[1]);
+    $entity->setNewRevision();
+    $entity->save();
+    $vids[] = $entity->getRevisionId();
 
     // Create revision 2
-    $rev[2] = entity_create($entity_type, array('id' => 0, 'revision_id' => 2, 'type' => $this->instance['bundle']));
-    $rev[2]->{$this->field_name} = $values;
-    field_attach_update($rev[2]);
+    $entity->setNewRevision();
+    $entity->save();
+    $vids[] = $entity->getRevisionId();
+    $controller = $this->container->get('plugin.manager.entity')->getStorageController($entity->entityType());
+    $controller->resetCache();
 
     // Confirm each revision loads
-    foreach (array_keys($rev) as $vid) {
-      $read = entity_create($entity_type, array('id' => 0, 'revision_id' => $vid, 'type' => $this->instance['bundle']));
-      field_attach_load_revision($entity_type, array(0 => $read));
-      $this->assertEqual(count($read->{$this->field_name}), $this->field['cardinality'], "The test entity revision $vid has {$this->field['cardinality']} values.");
+    foreach ($vids as $vid) {
+      $revision = $controller->loadRevision($vid);
+      $this->assertEqual(count($revision->{$this->field_name}), $this->field['cardinality'], "The test entity revision $vid has {$this->field['cardinality']} values.");
     }
 
     // Delete revision 1, confirm the other two still load.
-    field_attach_delete_revision($rev[1]);
-    foreach (array(0, 2) as $vid) {
-      $read = entity_create($entity_type, array('id' => 0, 'revision_id' => $vid, 'type' => $this->instance['bundle']));
-      field_attach_load_revision($entity_type, array(0 => $read));
-      $this->assertEqual(count($read->{$this->field_name}), $this->field['cardinality'], "The test entity revision $vid has {$this->field['cardinality']} values.");
+    $controller->deleteRevision($vids[1]);
+    $controller->resetCache();
+    foreach (array(0, 2) as $key) {
+      $vid = $vids[$key];
+      $revision = $controller->loadRevision($vid);
+      $this->assertEqual(count($revision->{$this->field_name}), $this->field['cardinality'], "The test entity revision $vid has {$this->field['cardinality']} values.");
     }
 
     // Confirm the current revision still loads
-    $read = entity_create($entity_type, array('id' => 0, 'revision_id' => 2, 'type' => $this->instance['bundle']));
-    field_attach_load($entity_type, array(0 => $read));
-    $this->assertEqual(count($read->{$this->field_name}), $this->field['cardinality'], "The test entity current revision has {$this->field['cardinality']} values.");
+    $controller->resetCache();
+    $current = $controller->load($entity->id());
+    $this->assertEqual(count($current->{$this->field_name}), $this->field['cardinality'], "The test entity current revision has {$this->field['cardinality']} values.");
 
     // Delete all field data, confirm nothing loads
-    field_attach_delete($rev[2]);
+    $entity->delete();
+    $controller->resetCache();
     foreach (array(0, 1, 2) as $vid) {
-      $read = entity_create($entity_type, array('id' => 0, 'revision_id' => $vid, 'type' => $this->instance['bundle']));
-      field_attach_load_revision($entity_type, array(0 => $read));
-      $this->assertIdentical($read->{$this->field_name}[0]->getValue(), array(), "The test entity revision $vid is deleted.");
+      $revision = $controller->loadRevision($vid);
+      $this->assertFalse($revision);
     }
-    $read = entity_create($entity_type, array('id' => 0, 'revision_id' => 2, 'type' => $this->instance['bundle']));
-    field_attach_load($entity_type, array(0 => $read));
-    $this->assertIdentical($read->{$this->field_name}[0]->getValue(), array(), 'The test entity current revision is deleted.');
+    $this->assertFalse($controller->load($entity->id()));
   }
 
   /**
@@ -435,14 +319,11 @@ function testEntityCreateRenameBundle() {
     entity_create('field_instance', $this->instance_definition)->save();
 
     // Save an entity with data in the field.
-    $entity = entity_create($entity_type, array('id' => 0, 'revision_id' => 0, 'type' => $this->instance['bundle']));
+    $entity = entity_create($entity_type, array('type' => $this->instance['bundle']));
     $values = $this->_generateTestFieldValues($this->field['cardinality']);
     $entity->{$this->field_name} = $values;
-    field_attach_insert($entity);
-
     // Verify the field data is present on load.
-    $entity = entity_create($entity_type, array('id' => 0, 'revision_id' => 0, 'type' => $this->instance['bundle']));
-    field_attach_load($entity_type, array(0 => $entity));
+    $entity = $this->entitySaveReload($entity);
     $this->assertEqual(count($entity->{$this->field_name}), $this->field['cardinality'], "Data is retrieved for the new bundle");
 
     // Rename the bundle.
@@ -454,8 +335,9 @@ function testEntityCreateRenameBundle() {
     $this->assertIdentical($this->instance['bundle'], $new_bundle, "Bundle name has been updated in the instance.");
 
     // Verify the field data is present on load.
-    $entity = entity_create($entity_type, array('id' => 0, 'revision_id' => 0, 'type' => $this->instance['bundle']));
-    field_attach_load($entity_type, array(0 => $entity));
+    $controller = $this->container->get('plugin.manager.entity')->getStorageController($entity->entityType());
+    $controller->resetCache();
+    $entity = $controller->load($entity->id());
     $this->assertEqual(count($entity->{$this->field_name}), $this->field['cardinality'], "Bundle name has been updated in the field storage");
   }
 
@@ -476,7 +358,12 @@ function testEntityDeleteBundle() {
 
     // Create a second field for the test bundle
     $field_name = drupal_strtolower($this->randomName() . '_field_name');
-    $field = array('field_name' => $field_name, 'type' => 'test_field', 'cardinality' => 1);
+    $field = array(
+      'name' => $field_name,
+      'entity_type' => $entity_type,
+      'type' => 'test_field',
+      'cardinality' => 1,
+    );
     entity_create('field_entity', $field)->save();
     $instance = array(
       'field_name' => $field_name,
@@ -489,15 +376,13 @@ function testEntityDeleteBundle() {
     entity_create('field_instance', $instance)->save();
 
     // Save an entity with data for both fields
-    $entity = entity_create($entity_type, array('id' => 0, 'revision_id' => 0, 'type' => $this->instance['bundle']));
+    $entity = entity_create($entity_type, array('type' => $this->instance['bundle']));
     $values = $this->_generateTestFieldValues($this->field['cardinality']);
     $entity->{$this->field_name} = $values;
     $entity->{$field_name} = $this->_generateTestFieldValues(1);
-    field_attach_insert($entity);
+    $entity = $this->entitySaveReload($entity);
 
     // Verify the fields are present on load
-    $entity = entity_create($entity_type, array('id' => 0, 'revision_id' => 0, 'type' => $this->instance['bundle']));
-    field_attach_load($entity_type, array(0 => $entity));
     $this->assertEqual(count($entity->{$this->field_name}), 4, 'First field got loaded');
     $this->assertEqual(count($entity->{$field_name}), 1, 'Second field got loaded');
 
@@ -505,8 +390,10 @@ function testEntityDeleteBundle() {
     entity_test_delete_bundle($this->instance['bundle'], $entity_type);
 
     // Verify no data gets loaded
-    $entity = entity_create($entity_type, array('id' => 0, 'revision_id' => 0, 'type' => $this->instance['bundle']));
-    field_attach_load($entity_type, array(0 => $entity));
+    $controller = $this->container->get('plugin.manager.entity')->getStorageController($entity->entityType());
+    $controller->resetCache();
+    $entity= $controller->load($entity->id());
+
     $this->assertTrue(empty($entity->{$this->field_name}), 'No data for first field');
     $this->assertTrue(empty($entity->{$field_name}), 'No data for second field');
 
diff --git a/core/modules/field/lib/Drupal/field/Tests/FieldInfoTest.php b/core/modules/field/lib/Drupal/field/Tests/FieldInfoTest.php
index 012ee4f..b5aba10 100644
--- a/core/modules/field/lib/Drupal/field/Tests/FieldInfoTest.php
+++ b/core/modules/field/lib/Drupal/field/Tests/FieldInfoTest.php
@@ -32,15 +32,6 @@ function testFieldInfo() {
       $this->assertEqual($info[$t_key]['module'], 'field_test',  'Field type field_test module appears.');
     }
 
-    $storage_info = field_test_field_storage_info();
-    $info = field_info_storage_types();
-    foreach ($storage_info as $s_key => $storage) {
-      foreach ($storage as $key => $val) {
-        $this->assertEqual($info[$s_key][$key], $val, format_string('Storage type %s_key key %key is %value', array('%s_key' => $s_key, '%key' => $key, '%value' => print_r($val, TRUE))));
-      }
-      $this->assertEqual($info[$s_key]['module'], 'field_test',  'Storage type field_test module appears.');
-    }
-
     // Verify that no unexpected instances exist.
     $instances = field_info_instances('entity_test');
     $expected = array();
@@ -121,7 +112,8 @@ function testFieldInfo() {
    */
   function testFieldPrepare() {
     $field_definition = array(
-      'field_name' => 'field',
+      'name' => 'field',
+      'entity_type' => 'entity_test',
       'type' => 'test_field',
     );
     $field = entity_create('field_entity', $field_definition);
@@ -130,13 +122,13 @@ function testFieldPrepare() {
     // Simulate a stored field definition missing a field setting (e.g. a
     // third-party module adding a new field setting has been enabled, and
     // existing fields do not know the setting yet).
-    \Drupal::config('field.field.' . $field->id())
+    \Drupal::config('field.field.' . $field->getFieldName())
       ->set('settings', array())
       ->save();
     field_info_cache_clear();
 
     // Read the field back.
-    $field = field_info_field($field_definition['field_name']);
+    $field = field_info_field('entity_test', $field_definition['field_name']);
 
     // Check that all expected settings are in place.
     $field_type = field_info_field_types($field_definition['type']);
@@ -148,7 +140,8 @@ function testFieldPrepare() {
    */
   function testInstancePrepare() {
     $field_definition = array(
-      'field_name' => 'field',
+      'name' => 'field',
+      'entity_type' => 'entity_test',
       'type' => 'test_field',
     );
     entity_create('field_entity', $field_definition)->save();
@@ -183,7 +176,8 @@ function testInstanceDisabledEntityType() {
     // For this test the field type and the entity type must be exposed by
     // different modules.
     $field_definition = array(
-      'field_name' => 'field',
+      'name' => 'field',
+      'entity_type' => 'comment',
       'type' => 'test_field',
     );
     entity_create('field_entity', $field_definition)->save();
@@ -192,7 +186,14 @@ function testInstanceDisabledEntityType() {
       'entity_type' => 'comment',
       'bundle' => 'comment_node_article',
     );
-    entity_create('field_instance', $instance_definition)->save();
+    $instance = entity_create('field_instance', $instance_definition);
+    try {
+      $instance->save();
+      $this->fail('No exception was thrown');
+    }
+    catch (\InvalidArgumentException $e) {
+      $this->assertEqual($e->getMessage(), 'The comment entity type does not exist.');
+    }
 
     // Disable coment module. This clears field_info cache.
     module_disable(array('comment'));
@@ -212,11 +213,18 @@ function testFieldMap() {
     // Create a couple fields.
     $fields  = array(
       array(
-        'field_name' => 'field_1',
+        'name' => 'field_1',
+        'entity_type' => 'entity_test',
         'type' => 'test_field',
       ),
       array(
-        'field_name' => 'field_2',
+        'name' => 'field_2',
+        'entity_type' => 'entity_test',
+        'type' => 'hidden_test_field',
+      ),
+      array(
+        'name' => 'field_2',
+        'entity_type' => 'entity_test_cache',
         'type' => 'hidden_test_field',
       ),
     );
@@ -302,7 +310,8 @@ function testFieldInfoCache() {
     // field_info_fields().
     $field_name = drupal_strtolower($this->randomName());
     $field = entity_create('field_entity', array(
-      'field_name' => $field_name,
+      'name' => $field_name,
+      'entity_type' => 'entity_test',
       'type' => 'test_field',
     ));
     $field->save();
diff --git a/core/modules/field/lib/Drupal/field/Tests/FieldInstanceCrudTest.php b/core/modules/field/lib/Drupal/field/Tests/FieldInstanceCrudTest.php
index 29e6cb2..ffd10c4 100644
--- a/core/modules/field/lib/Drupal/field/Tests/FieldInstanceCrudTest.php
+++ b/core/modules/field/lib/Drupal/field/Tests/FieldInstanceCrudTest.php
@@ -44,14 +44,14 @@ function setUp() {
     parent::setUp();
 
     $this->field_definition = array(
-      'field_name' => drupal_strtolower($this->randomName()),
+      'name' => drupal_strtolower($this->randomName()),
+      'entity_type' => 'entity_test',
       'type' => 'test_field',
     );
     $this->field = entity_create('field_entity', $this->field_definition);
     $this->field->save();
     $this->instance_definition = array(
       'field_name' => $this->field['field_name'],
-      'entity_type' => 'entity_test',
       'bundle' => 'entity_test',
     );
   }
@@ -103,40 +103,6 @@ function testCreateFieldInstance() {
       $this->pass(t('Cannot create an instance of a non-existing field.'));
     }
 
-    // Create a field restricted to a specific entity type.
-    $field_restricted_definition = array(
-      'field_name' => drupal_strtolower($this->randomName()),
-      'type' => 'test_field',
-      'entity_types' => array('entity_test_cache'),
-    );
-    $field_restricted = entity_create('field_entity', $field_restricted_definition);
-    $field_restricted->save();
-
-    // Check that an instance can be added to an entity type allowed
-    // by the field.
-    try {
-      $instance = $this->instance_definition;
-      $instance['field_name'] = $field_restricted_definition['field_name'];
-      $instance['entity_type'] = 'entity_test_cache';
-      entity_create('field_instance', $instance)->save();
-      $this->pass(t('Can create an instance on an entity type allowed by the field.'));
-    }
-    catch (FieldException $e) {
-      $this->fail(t('Can create an instance on an entity type allowed by the field.'));
-    }
-
-    // Check that an instance cannot be added to an entity type
-    // forbidden by the field.
-    try {
-      $instance = $this->instance_definition;
-      $instance['field_name'] = $field_restricted_definition['field_name'];
-      entity_create('field_instance', $instance)->save();
-      $this->fail(t('Cannot create an instance on an entity type forbidden by the field.'));
-    }
-    catch (FieldException $e) {
-      $this->pass(t('Cannot create an instance on an entity type forbidden by the field.'));
-    }
-
     // TODO: test other failures.
   }
 
diff --git a/core/modules/field/lib/Drupal/field/Tests/FieldUnitTestBase.php b/core/modules/field/lib/Drupal/field/Tests/FieldUnitTestBase.php
index 4580e7b..7ba1a18 100644
--- a/core/modules/field/lib/Drupal/field/Tests/FieldUnitTestBase.php
+++ b/core/modules/field/lib/Drupal/field/Tests/FieldUnitTestBase.php
@@ -20,7 +20,7 @@
    *
    * @var array
    */
-  public static $modules = array('user', 'entity', 'system', 'field', 'text', 'field_sql_storage', 'entity_test', 'field_test');
+  public static $modules = array('user', 'entity', 'system', 'field', 'text', 'entity_test', 'field_test');
 
   /**
    * A string for assert raw and text helper methods.
@@ -65,7 +65,12 @@ function createFieldWithInstance($suffix = '', $entity_type = 'entity_test', $bu
     $instance_definition = 'instance_definition' . $suffix;
 
     $this->$field_name = drupal_strtolower($this->randomName() . '_field_name' . $suffix);
-    $this->$field = entity_create('field_entity', array('field_name' => $this->$field_name, 'type' => 'test_field', 'cardinality' => 4));
+    $this->$field = entity_create('field_entity', array(
+      'name' => $this->$field_name,
+      'entity_type' => $entity_type,
+      'type' => 'test_field',
+      'cardinality' => 4,
+    ));
     $this->$field->save();
     $this->$field_id = $this->{$field}['uuid'];
     $this->$instance_definition = array(
@@ -92,6 +97,16 @@ function createFieldWithInstance($suffix = '', $entity_type = 'entity_test', $bu
   }
 
   /**
+   * Save and reload an entity.
+   */
+  protected function entitySaveReload(EntityInterface $entity) {
+    $entity->save();
+    $controller = $this->container->get('plugin.manager.entity')->getStorageController($entity->entityType());
+    $controller->resetCache();
+    return $controller->load($entity->id());
+  }
+
+  /**
    * Generate random values for a field_test field.
    *
    * @param $cardinality
diff --git a/core/modules/field/lib/Drupal/field/Tests/FormTest.php b/core/modules/field/lib/Drupal/field/Tests/FormTest.php
index b7c600e..cabb961 100644
--- a/core/modules/field/lib/Drupal/field/Tests/FormTest.php
+++ b/core/modules/field/lib/Drupal/field/Tests/FormTest.php
@@ -61,9 +61,23 @@ function setUp() {
     $web_user = $this->drupalCreateUser(array('view test entity', 'administer entity_test content'));
     $this->drupalLogin($web_user);
 
-    $this->field_single = array('field_name' => 'field_single', 'type' => 'test_field');
-    $this->field_multiple = array('field_name' => 'field_multiple', 'type' => 'test_field', 'cardinality' => 4);
-    $this->field_unlimited = array('field_name' => 'field_unlimited', 'type' => 'test_field', 'cardinality' => FIELD_CARDINALITY_UNLIMITED);
+    $this->field_single = array(
+      'name' => 'field_single',
+      'entity_type' => 'entity_test',
+      'type' => 'test_field',
+    );
+    $this->field_multiple = array(
+      'name' => 'field_multiple',
+      'entity_type' => 'entity_test',
+      'type' => 'test_field',
+      'cardinality' => 4,
+    );
+    $this->field_unlimited = array(
+      'name' => 'field_unlimited',
+      'entity_type' => 'entity_test',
+      'type' => 'test_field',
+      'cardinality' => FIELD_CARDINALITY_UNLIMITED,
+    );
 
     $this->instance = array(
       'entity_type' => 'entity_test',
@@ -244,7 +258,7 @@ function testFieldFormSingleRequired() {
 
   function testFieldFormUnlimited() {
     $field = $this->field_unlimited;
-    $field_name = $field['field_name'];
+    $field_name = $field['name'];
     $this->instance['field_name'] = $field_name;
     entity_create('field_entity', $field)->save();
     entity_create('field_instance', $this->instance)->save();
@@ -342,7 +356,8 @@ function testFieldFormMultivalueWithRequiredRadio() {
 
     // Add a required radio field.
     entity_create('field_entity', array(
-      'field_name' => 'required_radio_test',
+      'name' => 'required_radio_test',
+      'entity_type' => 'entity_test',
       'type' => 'list_text',
       'settings' => array(
         'allowed_values' => array('yes' => 'yes', 'no' => 'no'),
@@ -378,7 +393,7 @@ function testFieldFormMultivalueWithRequiredRadio() {
 
   function testFieldFormJSAddMore() {
     $field = $this->field_unlimited;
-    $field_name = $field['field_name'];
+    $field_name = $field['name'];
     $this->instance['field_name'] = $field_name;
     entity_create('field_entity', $field)->save();
     entity_create('field_instance', $this->instance)->save();
@@ -440,7 +455,7 @@ function testFieldFormMultipleWidget() {
     // Create a field with fixed cardinality and an instance using a multiple
     // widget.
     $field = $this->field_multiple;
-    $field_name = $field['field_name'];
+    $field_name = $field['name'];
     $this->instance['field_name'] = $field_name;
     entity_create('field_entity', $field)->save();
     entity_create('field_instance', $this->instance)->save();
@@ -487,7 +502,7 @@ function testFieldFormMultipleWidget() {
   function testFieldFormAccess() {
     // Create a "regular" field.
     $field = $this->field_single;
-    $field_name = $field['field_name'];
+    $field_name = $field['name'];
     $entity_type = 'entity_test_rev';
     $instance = $this->instance;
     $instance['field_name'] = $field_name;
@@ -501,10 +516,11 @@ function testFieldFormAccess() {
 
     // Create a field with no edit access - see field_test_field_access().
     $field_no_access = array(
-      'field_name' => 'field_no_edit_access',
+      'name' => 'field_no_edit_access',
+      'entity_type' => $entity_type,
       'type' => 'test_field',
     );
-    $field_name_no_access = $field_no_access['field_name'];
+    $field_name_no_access = $field_no_access['name'];
     $instance_no_access = array(
       'field_name' => $field_name_no_access,
       'entity_type' => $entity_type,
@@ -577,7 +593,7 @@ function testFieldFormAccess() {
   function testFieldFormHiddenWidget() {
     $entity_type = 'entity_test_rev';
     $field = $this->field_single;
-    $field_name = $field['field_name'];
+    $field_name = $field['name'];
     $this->instance['field_name'] = $field_name;
     $this->instance['default_value'] = array(0 => array('value' => 99));
     $this->instance['entity_type'] = $entity_type;
diff --git a/core/modules/field/lib/Drupal/field/Tests/ShapeItemTest.php b/core/modules/field/lib/Drupal/field/Tests/ShapeItemTest.php
index 6f7f3a0..b54174f 100644
--- a/core/modules/field/lib/Drupal/field/Tests/ShapeItemTest.php
+++ b/core/modules/field/lib/Drupal/field/Tests/ShapeItemTest.php
@@ -42,7 +42,8 @@ public function setUp() {
 
     // Create an field field and instance for validation.
     $field = array(
-      'field_name' => $this->field_name,
+      'name' => $this->field_name,
+      'entity_type' => 'entity_test',
       'type' => 'shape',
     );
     entity_create('field_entity', $field)->save();
diff --git a/core/modules/field/lib/Drupal/field/Tests/TestItemTest.php b/core/modules/field/lib/Drupal/field/Tests/TestItemTest.php
index e8b85d1..b4c4aa4 100644
--- a/core/modules/field/lib/Drupal/field/Tests/TestItemTest.php
+++ b/core/modules/field/lib/Drupal/field/Tests/TestItemTest.php
@@ -42,7 +42,8 @@ public function setUp() {
 
     // Create an field field and instance for validation.
     $field = array(
-      'field_name' => $this->field_name,
+      'name' => $this->field_name,
+      'entity_type' => 'entity_test',
       'type' => 'test_field',
     );
     entity_create('field_entity', $field)->save();
diff --git a/core/modules/field/lib/Drupal/field/Tests/TranslationTest.php b/core/modules/field/lib/Drupal/field/Tests/TranslationTest.php
index ebf9722..977b8f0 100644
--- a/core/modules/field/lib/Drupal/field/Tests/TranslationTest.php
+++ b/core/modules/field/lib/Drupal/field/Tests/TranslationTest.php
@@ -85,7 +85,8 @@ function setUp() {
     $this->entity_type = 'entity_test';
 
     $this->field_definition = array(
-      'field_name' => $this->field_name,
+      'name' => $this->field_name,
+      'entity_type' => $this->entity_type,
       'type' => 'test_field',
       'cardinality' => 4,
       'translatable' => TRUE,
@@ -153,8 +154,7 @@ function testTranslatableFieldSaveLoad() {
     // Prepare the field translations.
     $entity_type = 'entity_test';
     field_test_entity_info_translatable($entity_type, TRUE);
-    $id = $revision_id = 1;
-    $entity = entity_create($entity_type, array('id' => $id, 'revision_id' => $revision_id, 'type' => $this->instance['bundle']));
+    $entity = entity_create($entity_type, array('type' => $this->instance['bundle']));
     $field_translations = array();
     $available_langcodes = field_available_languages($entity_type, $this->field);
     $this->assertTrue(count($available_langcodes) > 1, 'Field is translatable.');
@@ -165,10 +165,7 @@ function testTranslatableFieldSaveLoad() {
     }
 
     // Save and reload the field translations.
-    field_attach_insert($entity);
-    $entity = entity_create($entity_type, array('id' => $id, 'revision_id' => $revision_id, 'type' => $this->instance['bundle']));
-    $entity->langcode->value = reset($available_langcodes);
-    field_attach_load($entity_type, array($id => $entity));
+    $entity = $this->entitySaveReload($entity);
 
     // Check if the correct values were saved/loaded.
     foreach ($field_translations as $langcode => $items) {
@@ -182,7 +179,7 @@ function testTranslatableFieldSaveLoad() {
     // Test default values.
     $field_name_default = drupal_strtolower($this->randomName() . '_field_name');
     $field_definition = $this->field_definition;
-    $field_definition['field_name'] = $field_name_default;
+    $field_definition['name'] = $field_name_default;
     entity_create('field_entity', $field_definition)->save();
 
     $instance_definition = $this->instance_definition;
@@ -197,9 +194,7 @@ function testTranslatableFieldSaveLoad() {
     asort($translation_langcodes);
     $translation_langcodes = array_values($translation_langcodes);
 
-    $id++;
-    $revision_id++;
-    $values = array('id' => $id, 'revision_id' => $revision_id, 'type' => $instance['bundle'], 'langcode' => $translation_langcodes[0]);
+    $values = array('type' => $instance['bundle'], 'langcode' => $translation_langcodes[0]);
     $entity = entity_create($entity_type, $values);
     foreach ($translation_langcodes as $langcode) {
       $values[$this->field_name][$langcode] = $this->_generateTestFieldValues($this->field['cardinality']);
@@ -217,9 +212,7 @@ function testTranslatableFieldSaveLoad() {
 
     // Check that explicit empty values are not overridden with default values.
     foreach (array(NULL, array()) as $empty_items) {
-      $id++;
-      $revision_id++;
-      $values = array('id' => $id, 'revision_id' => $revision_id, 'type' => $instance['bundle'], 'langcode' => $translation_langcodes[0]);
+      $values = array('type' => $instance['bundle'], 'langcode' => $translation_langcodes[0]);
       $entity = entity_create($entity_type, $values);
       foreach ($translation_langcodes as $langcode) {
         $values[$this->field_name][$langcode] = $this->_generateTestFieldValues($this->field['cardinality']);
@@ -244,7 +237,8 @@ function testFieldDisplayLanguage() {
     // We need an additional field here to properly test display language
     // suggestions.
     $field = array(
-      'field_name' => $field_name,
+      'name' => $field_name,
+      'entity_type' => $entity_type,
       'type' => 'test_field',
       'cardinality' => 2,
       'translatable' => TRUE,
@@ -272,7 +266,7 @@ function testFieldDisplayLanguage() {
     // enabled.
     foreach ($instances as $instance) {
       $field_name = $instance['field_name'];
-      $field = field_info_field($field_name);
+      $field = $instance->getField();
       do {
         // Index 0 is reserved for the requested language, this way we ensure
         // that no field is actually populated with it.
diff --git a/core/modules/field/lib/Drupal/field/Tests/TranslationWebTest.php b/core/modules/field/lib/Drupal/field/Tests/TranslationWebTest.php
index df93f12..257918b 100644
--- a/core/modules/field/lib/Drupal/field/Tests/TranslationWebTest.php
+++ b/core/modules/field/lib/Drupal/field/Tests/TranslationWebTest.php
@@ -33,7 +33,7 @@ class TranslationWebTest extends FieldTestBase {
    *
    * @var string
    */
-  protected $entity_type = 'test_entity';
+  protected $entity_type = 'entity_test_rev';
 
   /**
    * The field to use in this test.
@@ -62,10 +62,9 @@ function setUp() {
 
     $this->field_name = drupal_strtolower($this->randomName() . '_field_name');
 
-    $this->entity_type = 'entity_test_rev';
-
     $field = array(
-      'field_name' => $this->field_name,
+      'name' => $this->field_name,
+      'entity_type' => $this->entity_type,
       'type' => 'test_field',
       'cardinality' => 4,
       'translatable' => TRUE,
diff --git a/core/modules/field/lib/Drupal/field/Tests/Views/ApiDataTest.php b/core/modules/field/lib/Drupal/field/Tests/Views/ApiDataTest.php
index 4bf2625..9953ecb 100644
--- a/core/modules/field/lib/Drupal/field/Tests/Views/ApiDataTest.php
+++ b/core/modules/field/lib/Drupal/field/Tests/Views/ApiDataTest.php
@@ -6,6 +6,7 @@
  */
 
 namespace Drupal\field\Tests\Views;
+use Drupal\Core\Entity\DatabaseStorageController;
 
 /**
  * Test the produced views_data.
@@ -84,8 +85,8 @@ function testViewsData() {
     // Check the table and the joins of the first field.
     // Attached to node only.
     $field = $this->fields[0];
-    $current_table = _field_sql_storage_tablename($field);
-    $revision_table = _field_sql_storage_revision_tablename($field);
+    $current_table = DatabaseStorageController::_fieldTableName($field);
+    $revision_table = DatabaseStorageController::_fieldRevisionTableName($field);
     $data[$current_table] = $views_data->get($current_table);
     $data[$revision_table] = $views_data->get($revision_table);
 
@@ -117,8 +118,8 @@ function testViewsData() {
     // Check the table and the joins of the second field.
     // Attached to both node and user.
     $field_2 = $this->fields[2];
-    $current_table_2 = _field_sql_storage_tablename($field_2);
-    $revision_table_2 = _field_sql_storage_revision_tablename($field_2);
+    $current_table_2 = DatabaseStorageController::_fieldTableName($field_2);
+    $revision_table_2 = DatabaseStorageController::_fieldRevisionTableName($field_2);
     $data[$current_table_2] = $views_data->get($current_table_2);
     $data[$revision_table_2] = $views_data->get($revision_table_2);
 
diff --git a/core/modules/field/lib/Drupal/field/Tests/Views/FieldTestBase.php b/core/modules/field/lib/Drupal/field/Tests/Views/FieldTestBase.php
index 3cba44c..91e3348 100644
--- a/core/modules/field/lib/Drupal/field/Tests/Views/FieldTestBase.php
+++ b/core/modules/field/lib/Drupal/field/Tests/Views/FieldTestBase.php
@@ -59,7 +59,11 @@ function setUpFields($amount = 3) {
     $field_names = array();
     for ($i = 0; $i < $amount; $i++) {
       $field_names[$i] = 'field_name_' . $i;
-      $field = array('field_name' => $field_names[$i], 'type' => 'text');
+      $field = array(
+        'name' => $field_names[$i],
+        'entity_type' => 'node',
+        'type' => 'text',
+      );
 
       $this->fields[$i] = $field = entity_create('field_entity', $field);
       $field->save();
diff --git a/core/modules/field/lib/Drupal/field/Tests/Views/HandlerFieldFieldTest.php b/core/modules/field/lib/Drupal/field/Tests/Views/HandlerFieldFieldTest.php
index 8658c52..763ca85 100644
--- a/core/modules/field/lib/Drupal/field/Tests/Views/HandlerFieldFieldTest.php
+++ b/core/modules/field/lib/Drupal/field/Tests/Views/HandlerFieldFieldTest.php
@@ -47,10 +47,20 @@ protected function setUp() {
     $this->setUpFields(3);
 
     // Setup a field with cardinality > 1.
-    $this->fields[3] = $field = entity_create('field_entity', array('field_name' => 'field_name_3', 'type' => 'text', 'cardinality' => FIELD_CARDINALITY_UNLIMITED));
+    $this->fields[3] = $field = entity_create('field_entity', array(
+      'name' => 'field_name_3',
+      'entity_type' => 'node',
+      'type' => 'text',
+      'cardinality' => FIELD_CARDINALITY_UNLIMITED,
+    ));
     $field->save();
     // Setup a field that will have no value.
-    $this->fields[4] = $field = entity_create('field_entity', array('field_name' => 'field_name_4', 'type' => 'text', 'cardinality' => FIELD_CARDINALITY_UNLIMITED));
+    $this->fields[4] = $field = entity_create('field_entity', array(
+      'name' => 'field_name_4',
+      'entity_type' => 'node',
+      'type' => 'text',
+      'cardinality' => FIELD_CARDINALITY_UNLIMITED,
+    ));
     $field->save();
 
     $this->setUpInstances();
diff --git a/core/modules/field/lib/Drupal/field/Tests/reEnableModuleFieldTest.php b/core/modules/field/lib/Drupal/field/Tests/reEnableModuleFieldTest.php
index 6d4ed4a..0b5400d 100644
--- a/core/modules/field/lib/Drupal/field/Tests/reEnableModuleFieldTest.php
+++ b/core/modules/field/lib/Drupal/field/Tests/reEnableModuleFieldTest.php
@@ -21,7 +21,6 @@ class reEnableModuleFieldTest extends WebTestBase {
    */
   public static $modules = array(
     'field',
-    'field_sql_storage',
     'node',
     // We use telephone module instead of test_field because test_field is
     // hidden and does not display on the admin/modules page.
@@ -51,7 +50,8 @@ function testReEnabledField() {
 
     // Add a telephone field to the article content type.
     $field = entity_create('field_entity', array(
-      'field_name' => 'field_telephone',
+      'name' => 'field_telephone',
+      'entity_type' => 'node',
       'type' => 'telephone',
     ));
     $field->save();
diff --git a/core/modules/field/tests/modules/field_test/field_test.module b/core/modules/field/tests/modules/field_test/field_test.module
index 800f4d4..3ab0c7e 100644
--- a/core/modules/field/tests/modules/field_test/field_test.module
+++ b/core/modules/field/tests/modules/field_test/field_test.module
@@ -18,7 +18,6 @@
 
 require_once __DIR__ . '/field_test.entity.inc';
 require_once __DIR__ . '/field_test.field.inc';
-require_once __DIR__ . '/field_test.storage.inc';
 
 /**
  * Implements hook_permission().
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
index 66c9911..3bbbae2 100644
--- a/core/modules/field/tests/modules/field_test/field_test.storage.inc
+++ b/core/modules/field/tests/modules/field_test/field_test.storage.inc
@@ -195,7 +195,7 @@ function field_test_field_storage_delete(EntityInterface $entity, $fields) {
   // does, is highly inefficient in our case...
   foreach (field_info_instances($entity->entityType(), $entity->bundle()) as $instance) {
     if (isset($fields[$instance['field_id']])) {
-      $field = field_info_field_by_id($instance['field_id']);
+      $field = $instance->getField();
       field_test_field_storage_purge($entity, $field, $instance);
     }
   }
@@ -403,7 +403,7 @@ function field_test_field_storage_delete_field($field) {
 function field_test_field_storage_delete_instance($instance) {
   $data = _field_test_storage_data();
 
-  $field = field_info_field($instance['field_name']);
+  $field = $instance->getField();
   $field_data = &$data[$field['uuid']];
   foreach (array('current', 'revisions') as $sub_table) {
     foreach ($field_data[$sub_table] as &$row) {
@@ -424,8 +424,8 @@ function field_test_entity_bundle_rename($entity_type, $bundle_old, $bundle_new)
 
   // 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 $field_name => $instance) {
-    $field = field_info_field_by_id($instance['field_id']);
+  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) {
diff --git a/core/modules/field/tests/modules/field_test_config/config/field.field.entity_test.field_test_import.yml b/core/modules/field/tests/modules/field_test_config/config/field.field.entity_test.field_test_import.yml
new file mode 100644
index 0000000..61165d7
--- /dev/null
+++ b/core/modules/field/tests/modules/field_test_config/config/field.field.entity_test.field_test_import.yml
@@ -0,0 +1,20 @@
+id: entity_test.field_test_import
+langcode: und
+name: field_test_import
+entity_type: entity_test
+type: text
+settings:
+  max_length: '255'
+module: text
+active: '1'
+storage:
+  type: field_sql_storage
+  settings: {  }
+  module: field_sql_storage
+  active: '1'
+locked: '0'
+cardinality: '1'
+translatable: false
+indexes:
+  format:
+    - format
diff --git a/core/modules/field/tests/modules/field_test_config/config/field.field.entity_test.field_test_import_2.yml b/core/modules/field/tests/modules/field_test_config/config/field.field.entity_test.field_test_import_2.yml
new file mode 100644
index 0000000..ad1cd9a
--- /dev/null
+++ b/core/modules/field/tests/modules/field_test_config/config/field.field.entity_test.field_test_import_2.yml
@@ -0,0 +1,20 @@
+id: entity_test.field_test_import_2
+langcode: und
+name: field_test_import_2
+entity_type: entity_test
+type: text
+settings:
+  max_length: '255'
+module: text
+active: '1'
+storage:
+  type: field_sql_storage
+  settings: {  }
+  module: field_sql_storage
+  active: '1'
+locked: '0'
+cardinality: '1'
+translatable: false
+indexes:
+  format:
+    - format
diff --git a/core/modules/field/tests/modules/field_test_config/config/field.field.field_test_import.yml b/core/modules/field/tests/modules/field_test_config/config/field.field.field_test_import.yml
deleted file mode 100644
index f472164..0000000
--- a/core/modules/field/tests/modules/field_test_config/config/field.field.field_test_import.yml
+++ /dev/null
@@ -1,19 +0,0 @@
-id: field_test_import
-langcode: und
-type: text
-settings:
-  max_length: '255'
-module: text
-active: '1'
-entity_types: {  }
-storage:
-  type: field_sql_storage
-  settings: {  }
-  module: field_sql_storage
-  active: '1'
-locked: '0'
-cardinality: '1'
-translatable: false
-indexes:
-  format:
-    - format
diff --git a/core/modules/field/tests/modules/field_test_config/config/field.field.field_test_import_2.yml b/core/modules/field/tests/modules/field_test_config/config/field.field.field_test_import_2.yml
deleted file mode 100644
index 4d508a9..0000000
--- a/core/modules/field/tests/modules/field_test_config/config/field.field.field_test_import_2.yml
+++ /dev/null
@@ -1,19 +0,0 @@
-id: field_test_import_2
-langcode: und
-type: text
-settings:
-  max_length: '255'
-module: text
-active: '1'
-entity_types: {  }
-storage:
-  type: field_sql_storage
-  settings: {  }
-  module: field_sql_storage
-  active: '1'
-locked: '0'
-cardinality: '1'
-translatable: false
-indexes:
-  format:
-    - format
diff --git a/core/modules/field/tests/modules/field_test_config/staging/field.field.entity_test.field_test_import_staging.yml b/core/modules/field/tests/modules/field_test_config/staging/field.field.entity_test.field_test_import_staging.yml
new file mode 100644
index 0000000..a15236e
--- /dev/null
+++ b/core/modules/field/tests/modules/field_test_config/staging/field.field.entity_test.field_test_import_staging.yml
@@ -0,0 +1,21 @@
+id: entity_test.field_test_import_staging
+uuid: 0bf654cc-f14a-4881-b94c-76959e47466b
+langcode: und
+name: field_test_import_staging
+entity_type: entity_test
+type: text
+settings:
+  max_length: '255'
+module: text
+active: '1'
+storage:
+  type: field_sql_storage
+  settings: {  }
+  module: field_sql_storage
+  active: '1'
+locked: '0'
+cardinality: '1'
+translatable: '0'
+indexes:
+  format:
+    - format
diff --git a/core/modules/field/tests/modules/field_test_config/staging/field.field.entity_test.field_test_import_staging_2.yml b/core/modules/field/tests/modules/field_test_config/staging/field.field.entity_test.field_test_import_staging_2.yml
new file mode 100644
index 0000000..851d816
--- /dev/null
+++ b/core/modules/field/tests/modules/field_test_config/staging/field.field.entity_test.field_test_import_staging_2.yml
@@ -0,0 +1,21 @@
+id: entity_test.field_test_import_staging_2
+uuid: 2165d9aa-9a0c-41a1-be02-2a49f3405c00
+langcode: und
+name: field_test_import_staging_2
+entity_test: entity_test
+type: text
+settings:
+  max_length: '255'
+module: text
+active: '1'
+storage:
+  type: field_sql_storage
+  settings: {  }
+  module: field_sql_storage
+  active: '1'
+locked: '0'
+cardinality: '1'
+translatable: '0'
+indexes:
+  format:
+    - format
diff --git a/core/modules/field/tests/modules/field_test_config/staging/field.field.field_test_import_staging.yml b/core/modules/field/tests/modules/field_test_config/staging/field.field.field_test_import_staging.yml
deleted file mode 100644
index 4226f72..0000000
--- a/core/modules/field/tests/modules/field_test_config/staging/field.field.field_test_import_staging.yml
+++ /dev/null
@@ -1,20 +0,0 @@
-id: field_test_import_staging
-uuid: 0bf654cc-f14a-4881-b94c-76959e47466b
-langcode: und
-type: text
-settings:
-  max_length: '255'
-module: text
-active: '1'
-entity_types: {  }
-storage:
-  type: field_sql_storage
-  settings: {  }
-  module: field_sql_storage
-  active: '1'
-locked: '0'
-cardinality: '1'
-translatable: '0'
-indexes:
-  format:
-    - format
diff --git a/core/modules/field/tests/modules/field_test_config/staging/field.field.field_test_import_staging_2.yml b/core/modules/field/tests/modules/field_test_config/staging/field.field.field_test_import_staging_2.yml
deleted file mode 100644
index a0eb94e..0000000
--- a/core/modules/field/tests/modules/field_test_config/staging/field.field.field_test_import_staging_2.yml
+++ /dev/null
@@ -1,20 +0,0 @@
-id: field_test_import_staging_2
-uuid: 2165d9aa-9a0c-41a1-be02-2a49f3405c00
-langcode: und
-type: text
-settings:
-  max_length: '255'
-module: text
-active: '1'
-entity_types: {  }
-storage:
-  type: field_sql_storage
-  settings: {  }
-  module: field_sql_storage
-  active: '1'
-locked: '0'
-cardinality: '1'
-translatable: '0'
-indexes:
-  format:
-    - format
diff --git a/core/modules/field_sql_storage/field_sql_storage.info.yml b/core/modules/field_sql_storage/field_sql_storage.info.yml
deleted file mode 100644
index e5172b5..0000000
--- a/core/modules/field_sql_storage/field_sql_storage.info.yml
+++ /dev/null
@@ -1,9 +0,0 @@
-name: 'Field SQL Storage'
-type: module
-description: 'Stores field data in an SQL database.'
-package: Core
-version: VERSION
-core: 8.x
-dependencies:
-  - field
-required: true
diff --git a/core/modules/field_sql_storage/field_sql_storage.install b/core/modules/field_sql_storage/field_sql_storage.install
deleted file mode 100644
index 8d14ca8..0000000
--- a/core/modules/field_sql_storage/field_sql_storage.install
+++ /dev/null
@@ -1,153 +0,0 @@
-<?php
-
-/**
- * @file
- * Install, update, and uninstall functions for the Field SQL Storage module.
- */
-
-use Drupal\field\Plugin\Core\Entity\Field;
-
-/**
- * Writes field data directly to SQL storage.
- *
- * @ingroup update_api
- */
-function _update_8000_field_sql_storage_write($entity_type, $bundle, $entity_id, $revision_id, $field_name, $data) {
-  $table_name = "field_data_{$field_name}";
-  $revision_name = "field_revision_{$field_name}";
-
-  db_delete($table_name)
-    ->condition('entity_type', $entity_type)
-    ->condition('entity_id', $entity_id)
-    ->execute();
-  db_delete($revision_name)
-    ->condition('entity_type', $entity_type)
-    ->condition('entity_id', $entity_id)
-    ->condition('revision_id', $revision_id)
-    ->execute();
-
-  $columns = array();
-  foreach ($data as $langcode => $items) {
-    foreach ($items as $delta => $item) {
-      $record = array(
-        'entity_type' => $entity_type,
-        'entity_id' => $entity_id,
-        'revision_id' => $revision_id,
-        'bundle' => $bundle,
-        'delta' => $delta,
-        'langcode' => $langcode,
-      );
-      foreach ($item as $column => $value) {
-        $record[_field_sql_storage_columnname($field_name, $column)] = $value;
-      }
-
-      $records[] = $record;
-      // Record the columns used.
-      $columns += $record;
-    }
-  }
-
-  if ($columns) {
-    $query = db_insert($table_name)->fields(array_keys($columns));
-    $revision_query = db_insert($revision_name)->fields(array_keys($columns));
-    foreach ($records as $record) {
-      $query->values($record);
-      if ($revision_id) {
-        $revision_query->values($record);
-      }
-    }
-    $query->execute();
-    $revision_query->execute();
-  }
-}
-
-/**
- * Implements hook_update_dependencies().
- */
-function field_sql_storage_update_dependencies() {
-  // Convert storage tables after field definitions have moved to
-  // ConfigEntities.
-  $dependencies['field_sql_storage'][8000] = array(
-    'field' => 8003,
-  );
-  return $dependencies;
-}
-
-/**
- * Renames the 'language' column to 'langcode' in field data tables.
- */
-function field_sql_storage_update_8000(&$sandbox) {
-  // Get field definitions from config, and deleted fields from state system.
-  $config_names = config_get_storage_names_with_prefix('field.field');
-  $deleted_fields = Drupal::state()->get('field.field.deleted') ?: array();
-  // Ditch UUID keys, we will iterate through deleted fields using a numeric
-  // index.
-  $deleted_fields = array_values($deleted_fields);
-
-  if (empty($config_names) && empty($deleted_fields)) {
-    return;
-  }
-
-  if (!isset($sandbox['index'])) {
-    $sandbox['index'] = 0;
-    $sandbox['max'] = count($config_names) + count($deleted_fields);
-  }
-
-  // Retrieve the next field definition. When the index exceeds the number of
-  // 'configuration' fields, use it to iterate on deleted fields.
-  if (isset($config_names[$sandbox['index']])) {
-    $field_config = config($config_names[$sandbox['index']])->get();
-  }
-  else {
-    $field_config = $deleted_fields[$sandbox['index'] - count($config_names)];
-  }
-
-  if ($field_config['storage']['type'] == 'field_sql_storage') {
-    $field = new Field($field_config);
-
-    // Prepare updated schema data structures.
-    $primary_key_data = array(
-      'entity_type',
-      'entity_id',
-      'deleted',
-      'delta',
-      'langcode',
-    );
-    $primary_key_revision = array(
-      'entity_type',
-      'entity_id',
-      'revision_id',
-      'deleted',
-      'delta',
-      'langcode',
-    );
-    $langcode_index = array(
-      'langcode',
-    );
-    $field_langcode = array(
-      'type' => 'varchar',
-      'length' => 32,
-      'not null' => TRUE,
-      'default' => '',
-    );
-
-    $table_info = array(
-      _field_sql_storage_tablename($field) => $primary_key_data,
-      _field_sql_storage_revision_tablename($field) => $primary_key_revision,
-    );
-    foreach ($table_info as $table => $primary_key) {
-      // Do not update tables which already have the langcode column,
-      // created during the upgrade before this update function.
-      if (db_field_exists($table, 'language')) {
-        db_drop_primary_key($table);
-        db_drop_index($table, 'language');
-        db_change_field($table, 'language', 'langcode', $field_langcode);
-        db_add_primary_key($table, $primary_key);
-        db_add_index($table, 'langcode', $langcode_index);
-      }
-    }
-  }
-
-  $sandbox['index']++;
-  $sandbox['#finished'] = empty($sandbox['max']) ? 1 : ($sandbox['index'] / $sandbox['max']);
-}
diff --git a/core/modules/field_ui/field_ui.module b/core/modules/field_ui/field_ui.module
index 2040df2..1d94c70 100644
--- a/core/modules/field_ui/field_ui.module
+++ b/core/modules/field_ui/field_ui.module
@@ -216,7 +216,7 @@ function field_ui_instance_load($field_name, $entity_type, $bundle_name, $bundle
     $bundle_name = field_extract_bundle($entity_type, $bundle);
   }
   // Check whether the field exists at all.
-  if ($field = field_info_field($field_name)) {
+  if ($field = field_info_field($entity_type, $field_name)) {
     // Only return the field if a field instance exists for the given entity
     // type and bundle.
     if ($instance = field_info_instance($entity_type, $field_name, $bundle_name)) {
diff --git a/core/modules/field_ui/lib/Drupal/field_ui/FieldOverview.php b/core/modules/field_ui/lib/Drupal/field_ui/FieldOverview.php
index 8e7e770..6495cde 100644
--- a/core/modules/field_ui/lib/Drupal/field_ui/FieldOverview.php
+++ b/core/modules/field_ui/lib/Drupal/field_ui/FieldOverview.php
@@ -74,7 +74,7 @@ public function buildForm(array $form, array &$form_state, $entity_type = NULL,
 
     // Fields.
     foreach ($instances as $name => $instance) {
-      $field = field_info_field($instance['field_name']);
+      $field = $instance->getField();
       $admin_field_path = $this->adminPath . '/fields/' . $instance->id();
       $table[$name] = array(
         '#attributes' => array(
@@ -336,12 +336,13 @@ public function submitForm(array &$form, array &$form_state) {
       $values = $form_values['_add_new_field'];
 
       $field = array(
-        'field_name' => $values['field_name'],
+        'name' => $values['field_name'],
+        'entity_type' => $this->entity_type,
         'type' => $values['type'],
         'translatable' => $values['translatable'],
       );
       $instance = array(
-        'field_name' => $field['field_name'],
+        'field_name' => $values['field_name'],
         'entity_type' => $this->entity_type,
         'bundle' => $this->bundle,
         'label' => $values['label'],
@@ -357,14 +358,14 @@ public function submitForm(array &$form, array &$form_state) {
         // default widget and settings). It stays hidden for other form modes
         // until it is explicitly configured.
         entity_get_form_display($this->entity_type, $this->bundle, 'default')
-          ->setComponent($field['field_name'])
+          ->setComponent($values['field_name'])
           ->save();
 
         // Make sure the field is displayed in the 'default' view mode (using
         // default formatter and settings). It stays hidden for other view
         // modes until it is explicitly configured.
         entity_get_display($this->entity_type, $this->bundle, 'default')
-          ->setComponent($field['field_name'])
+          ->setComponent($values['field_name'])
           ->save();
 
         // Always show the field settings step, as the cardinality needs to be
@@ -373,7 +374,7 @@ public function submitForm(array &$form, array &$form_state) {
         $destinations[] = $this->adminPath . '/fields/' . $new_instance->id();
 
         // Store new field information for any additional submit handlers.
-        $form_state['fields_added']['_add_new_field'] = $field['field_name'];
+        $form_state['fields_added']['_add_new_field'] = $values['field_name'];
       }
       catch (\Exception $e) {
         drupal_set_message(t('There was a problem creating field %label: !message', array('%label' => $instance['label'], '!message' => $e->getMessage())), 'error');
@@ -383,7 +384,7 @@ public function submitForm(array &$form, array &$form_state) {
     // Re-use existing field.
     if (!empty($form_values['_add_existing_field']['field_name'])) {
       $values = $form_values['_add_existing_field'];
-      $field = field_info_field($values['field_name']);
+      $field = field_info_field($this->entity_type, $values['field_name']);
       if (!empty($field['locked'])) {
         drupal_set_message(t('The field %label cannot be added because it is locked.', array('%label' => $values['label'])), 'error');
       }
@@ -444,37 +445,41 @@ public function submitForm(array &$form, array &$form_state) {
    *   An array of existing fields keyed by field name.
    */
   protected function getExistingFieldOptions() {
-    $info = array();
-    $field_types = field_info_field_types();
+    $options = array();
 
-    foreach (field_info_instances() as $existing_entity_type => $bundles) {
-      foreach ($bundles as $existing_bundle => $instances) {
-        // No need to look in the current bundle.
-        if (!($existing_bundle == $this->bundle && $existing_entity_type == $this->entity_type)) {
-          foreach ($instances as $instance) {
-            $field = field_info_field($instance['field_name']);
-            // Don't show
-            // - locked fields,
-            // - fields already in the current bundle,
-            // - fields that cannot be added to the entity type,
-            // - fields that should not be added via user interface.
+    // Collect candidate field instances.
+    $field_map = field_info_field_map();
+    $instance_ids = array();
+    foreach ($field_map as $field_name => $data) {
+      // @todo do not consider the current bundle.
 
-            if (empty($field['locked'])
-              && !field_info_instance($this->entity_type, $field['field_name'], $this->bundle)
-              && (empty($field['entity_types']) || in_array($this->entity_type, $field['entity_types']))
-              && empty($field_types[$field['type']]['no_ui'])) {
-              $info[$instance['field_name']] = array(
-                'type' => $field['type'],
-                'type_label' => $field_types[$field['type']]['label'],
-                'field' => $field['field_name'],
-                'label' => $instance['label'],
-              );
-            }
-          }
+      if (isset($data['bundles'][$this->entity_type]) && !in_array($this->bundle, $data['bundles'][$this->entity_type])) {
+        $bundle = reset($data['bundles'][$this->entity_type]);
+        $instance_ids[] = $this->entity_type . '.' . $bundle . '.' . $field_name;
+      }
+    }
+
+    // Load the instances and build the list of options.
+    if ($instance_ids) {
+      $field_types = field_info_field_types();
+      $instances = $this->entityManager->getStorageController('field_instance')->loadMultiple($instance_ids);
+      foreach ($instances as $instance) {
+        $field = $instance->getField();
+        // Do not show:
+        // - locked fields,
+        // - fields that should not be added via user interface.
+        if (empty($field['locked']) && empty($field_types[$field['type']]['no_ui'])) {
+          $options[$field->name] = array(
+            'type' => $field->type,
+            'type_label' => $field_types[$field->type]['label'],
+            'field' => $field->name,
+            'label' => $instance->label,
+          );
         }
       }
     }
-    return $info;
+
+    return $options;
   }
 
   /**
diff --git a/core/modules/field_ui/lib/Drupal/field_ui/Form/FieldEditForm.php b/core/modules/field_ui/lib/Drupal/field_ui/Form/FieldEditForm.php
index 305596f..65c5207 100644
--- a/core/modules/field_ui/lib/Drupal/field_ui/Form/FieldEditForm.php
+++ b/core/modules/field_ui/lib/Drupal/field_ui/Form/FieldEditForm.php
@@ -174,7 +174,7 @@ public function submitForm(array &$form, array &$form_state) {
     unset($field_values['container']);
 
     // Merge incoming form values into the existing field.
-    $field = Field::fieldInfo()->getField($field_values['field_name']);
+    $field = $this->instance->getField();
     foreach ($field_values as $key => $value) {
       $field[$key] = $value;
     }
diff --git a/core/modules/field_ui/lib/Drupal/field_ui/Form/FieldInstanceEditForm.php b/core/modules/field_ui/lib/Drupal/field_ui/Form/FieldInstanceEditForm.php
index 26264ac..90b0f28 100644
--- a/core/modules/field_ui/lib/Drupal/field_ui/Form/FieldInstanceEditForm.php
+++ b/core/modules/field_ui/lib/Drupal/field_ui/Form/FieldInstanceEditForm.php
@@ -136,7 +136,7 @@ public function validateForm(array &$form, array &$form_state) {
 
       // Extract the 'default value'.
       $items = array();
-      $entity_form_display->getRenderer($this->instance->getField()->id)->extractFormValues($entity, Language::LANGCODE_NOT_SPECIFIED, $items, $element, $form_state);
+      $entity_form_display->getRenderer($this->instance->getField()->name)->extractFormValues($entity, Language::LANGCODE_NOT_SPECIFIED, $items, $element, $form_state);
 
       // @todo Simplify when all entity types are converted to EntityNG.
       if ($entity instanceof EntityNG) {
@@ -160,7 +160,7 @@ public function validateForm(array &$form, array &$form_state) {
         field_form_set_state($element['#parents'], $field_name, Language::LANGCODE_NOT_SPECIFIED, $form_state, $field_state);
 
         // Assign reported errors to the correct form element.
-        $entity_form_display->getRenderer($this->instance->getField()->id)->flagErrors($entity, Language::LANGCODE_NOT_SPECIFIED, $items, $element, $form_state);
+        $entity_form_display->getRenderer($this->instance->getField()->name)->flagErrors($entity, Language::LANGCODE_NOT_SPECIFIED, $items, $element, $form_state);
       }
     }
   }
@@ -178,7 +178,7 @@ public function submitForm(array &$form, array &$form_state) {
 
       // Extract field values.
       $items = array();
-      $entity_form_display->getRenderer($this->instance->getField()->id)->extractFormValues($entity, Language::LANGCODE_NOT_SPECIFIED, $items, $element, $form_state);
+      $entity_form_display->getRenderer($this->instance->getField()->name)->extractFormValues($entity, Language::LANGCODE_NOT_SPECIFIED, $items, $element, $form_state);
 
       $this->instance['default_value'] = $items ? $items : NULL;
     }
@@ -250,7 +250,7 @@ protected function getDefaultValueWidget($field, array &$form, &$form_state) {
     if (!empty($this->instance['default_value'])) {
       $items = (array) $this->instance['default_value'];
     }
-    $element += $entity_form_display->getRenderer($this->instance->getField()->id)->form($entity, Language::LANGCODE_NOT_SPECIFIED, $items, $element, $form_state);
+    $element += $entity_form_display->getRenderer($this->instance->getField()->name)->form($entity, Language::LANGCODE_NOT_SPECIFIED, $items, $element, $form_state);
 
     return $element;
   }
diff --git a/core/modules/field_ui/lib/Drupal/field_ui/Tests/ManageFieldsTest.php b/core/modules/field_ui/lib/Drupal/field_ui/Tests/ManageFieldsTest.php
index 645ae95..62a38af 100644
--- a/core/modules/field_ui/lib/Drupal/field_ui/Tests/ManageFieldsTest.php
+++ b/core/modules/field_ui/lib/Drupal/field_ui/Tests/ManageFieldsTest.php
@@ -42,7 +42,8 @@ function setUp() {
     $vocabulary->save();
 
     $field = array(
-      'field_name' => 'field_' . $vocabulary->id(),
+      'name' => 'field_' . $vocabulary->id(),
+      'entity_type' => 'node',
       'type' => 'taxonomy_term_reference',
     );
     entity_create('field_entity', $field)->save();
@@ -231,7 +232,7 @@ function assertFieldSettings($bundle, $field_name, $string = 'dummy test string'
     // Reset the fields info.
     field_info_cache_clear();
     // Assert field settings.
-    $field = field_info_field($field_name);
+    $field = field_info_field($entity_type, $field_name);
     $this->assertTrue($field['settings']['test_field_setting'] == $string, 'Field settings were found.');
 
     // Assert instance settings.
@@ -276,7 +277,8 @@ function testDefaultValue() {
     // Create a test field and instance.
     $field_name = 'test';
     entity_create('field_entity', array(
-      'field_name' => $field_name,
+      'name' => $field_name,
+      'entity_type' => 'node',
       'type' => 'test_field'
     ))->save();
     $instance = entity_create('field_instance', array(
@@ -386,7 +388,8 @@ function testLockedField() {
     // Create a locked field and attach it to a bundle. We need to do this
     // programatically as there's no way to create a locked field through UI.
     $field = entity_create('field_entity', array(
-      'field_name' => strtolower($this->randomName(8)),
+      'name' => strtolower($this->randomName(8)),
+      'entity_type' => 'node',
       'type' => 'test_field',
       'cardinality' => 1,
       'locked' => TRUE
@@ -405,11 +408,11 @@ function testLockedField() {
 
     // Check that the links for edit and delete are not present.
     $this->drupalGet('admin/structure/types/manage/' . $this->type . '/fields');
-    $locked = $this->xpath('//tr[@id=:field_name]/td[4]', array(':field_name' => $field->id()));
+    $locked = $this->xpath('//tr[@id=:field_name]/td[4]', array(':field_name' => $field->getFieldName()));
     $this->assertTrue(in_array('Locked', $locked), 'Field is marked as Locked in the UI');
-    $edit_link = $this->xpath('//tr[@id=:field_name]/td[4]', array(':field_name' => $field->id()));
+    $edit_link = $this->xpath('//tr[@id=:field_name]/td[4]', array(':field_name' => $field->getFieldName()));
     $this->assertFalse(in_array('edit', $edit_link), 'Edit option for locked field is not present the UI');
-    $delete_link = $this->xpath('//tr[@id=:field_name]/td[4]', array(':field_name' => $field->id()));
+    $delete_link = $this->xpath('//tr[@id=:field_name]/td[4]', array(':field_name' => $field->getFieldName()));
     $this->assertFalse(in_array('delete', $delete_link), 'Delete option for locked field is not present the UI');
   }
 
@@ -425,7 +428,11 @@ function testHiddenFields() {
 
     // Create a field and an instance programmatically.
     $field_name = 'hidden_test_field';
-    entity_create('field_entity', array('field_name' => $field_name, 'type' => $field_name))->save();
+    entity_create('field_entity', array(
+      'name' => $field_name,
+      'entity_type' => 'node',
+      'type' => $field_name,
+    ))->save();
     $instance = array(
       'field_name' => $field_name,
       'bundle' => $this->type,
@@ -501,7 +508,7 @@ function testDeleteTaxonomyField() {
     // Check that the field instance was deleted.
     $this->assertNull(field_info_instance('taxonomy_term', $this->field_name, 'tags'), 'Field instance was deleted.');
     // Check that the field was deleted too.
-    $this->assertNull(field_info_field($this->field_name), 'Field was deleted.');
+    $this->assertNull(field_info_field('taxonomy_term', $this->field_name), 'Field was deleted.');
   }
 
   /**
@@ -510,7 +517,8 @@ function testDeleteTaxonomyField() {
   function testHelpDescriptions() {
     // Create an image field
     entity_create('field_entity', array(
-      'field_name' => 'field_image',
+      'name' => 'field_image',
+      'entity_type' => 'node',
       'type' => 'image',
     ))->save();
 
diff --git a/core/modules/file/file.install b/core/modules/file/file.install
index 1f31e43..8bc43b3 100644
--- a/core/modules/file/file.install
+++ b/core/modules/file/file.install
@@ -5,6 +5,7 @@
  * Install, update and uninstall functions for File module.
  */
 
+use Drupal\Core\Entity\DatabaseStorageController;
 use Drupal\field\Plugin\Core\Entity\Field;
 
 /**
@@ -304,12 +305,12 @@ function file_update_8003() {
   foreach (config_get_storage_names_with_prefix('field.field.') as $config_name) {
     $field_config = config($config_name);
     // Only update file fields that use the default SQL storage.
-    if (in_array($field_config->get('type'), array('file', 'image')) && $field_config->get('storage.type') == 'field_sql_storage') {
+    if (in_array($field_config->get('type'), array('file', 'image'))) {
       $field = new Field($field_config->get());
 
       $tables = array(
-        _field_sql_storage_tablename($field),
-        _field_sql_storage_revision_tablename($field),
+        DatabaseStorageController::_fieldTableName($field),
+        DatabaseStorageController::_fieldRevisionTableName($field),
       );
 
       foreach ($tables as $table_name) {
diff --git a/core/modules/file/file.module b/core/modules/file/file.module
index 0d66adb..76758c9 100644
--- a/core/modules/file/file.module
+++ b/core/modules/file/file.module
@@ -650,7 +650,7 @@ function file_file_download($uri, $field_type = 'file') {
   foreach ($references as $field_name => $field_references) {
     foreach ($field_references as $entity_type => $entities) {
       foreach ($entities as $entity) {
-        $field = field_info_field($field_name);
+        $field = field_info_field($entity_type, $field_name);
         // Check if access to this field is not disallowed.
         if (!field_access('view', $field, $entity_type, $entity)) {
           $denied = TRUE;
@@ -1587,7 +1587,7 @@ function file_get_file_references(File $file, $field = NULL, $age = FIELD_LOAD_R
           // This contains the possible field names.
           $instances = field_info_instances($entity_type, $bundle);
           foreach ($instances as $field_name => $instance) {
-            $current_field = field_info_field($field_name);
+            $current_field = $instance->getField();
             // If this is the first time this field type is seen, check
             // whether it references files.
             if (!isset($field_columns[$current_field['type']])) {
@@ -1624,10 +1624,11 @@ function file_get_file_references(File $file, $field = NULL, $age = FIELD_LOAD_R
   // Filter the static cache down to the requested entries. The usual static
   // cache is very small so this will be very fast.
   if ($field || $field_type) {
-    foreach ($return as $field_name => $data) {
-      $current_field = field_info_field($field_name);
+    $fields = entity_load_multiple('field_entity', array_keys($return));
+    foreach ($return as $field_id => $data) {
+      $current_field = $fields[$field_id];
       if (($field_type && $current_field['type'] != $field_type) || ($field && $field['id'] != $current_field['id'])) {
-        unset($return[$field_name]);
+        unset($return[$field_id]);
       }
     }
   }
diff --git a/core/modules/file/file.views.inc b/core/modules/file/file.views.inc
index 5c2743f..000f600 100644
--- a/core/modules/file/file.views.inc
+++ b/core/modules/file/file.views.inc
@@ -6,6 +6,7 @@
  *
  * @ingroup views_module_handlers
  */
+use Drupal\Core\Entity\DatabaseStorageController;
 
 /**
  * Implements hook_views_data().
@@ -451,8 +452,8 @@ function file_views_data() {
  *
  * @see field_views_field_default_views_data()
  */
-function file_field_views_data($field) {
-  $data = field_views_field_default_views_data($field);
+function file_field_views_data($field, $sql_entity_types) {
+  $data = field_views_field_default_views_data($field, $sql_entity_types);
   foreach ($data as $table_name => $table_data) {
     // Add the relationship only on the fid field.
     $data[$table_name][$field['field_name'] . '_target_id']['relationship'] = array(
@@ -472,8 +473,8 @@ function file_field_views_data($field) {
  *
  * Views integration to provide reverse relationships on file fields.
  */
-function file_field_views_data_views_data_alter(&$data, $field) {
-  foreach ($field['bundles'] as $entity_type => $bundles) {
+function file_field_views_data_views_data_alter(&$data, $field, $sql_entity_types) {
+  foreach ($sql_entity_types as $entity_type) {
     $entity_info = entity_get_info($entity_type);
     $pseudo_field_name = 'reverse_' . $field['field_name'] . '_' . $entity_type;
 
@@ -488,7 +489,7 @@ function file_field_views_data_views_data_alter(&$data, $field) {
       'help' => t('Relate each @entity with a @field set to the file.', array('@entity' => $entity, '@field' => $label)),
       'id' => 'entity_reverse',
       'field_name' => $field['field_name'],
-      'field table' => _field_sql_storage_tablename($field),
+      'field table' => DatabaseStorageController::_fieldTableName($field),
       'field field' => $field['field_name'] . '_target_id',
       'base' => $entity_info['base_table'],
       'base field' => $entity_info['entity_keys']['id'],
diff --git a/core/modules/file/lib/Drupal/file/Tests/FileFieldDisplayTest.php b/core/modules/file/lib/Drupal/file/Tests/FileFieldDisplayTest.php
index 29ba4ef..7e32985 100644
--- a/core/modules/file/lib/Drupal/file/Tests/FileFieldDisplayTest.php
+++ b/core/modules/file/lib/Drupal/file/Tests/FileFieldDisplayTest.php
@@ -36,7 +36,7 @@ function testNodeDisplay() {
       'description_field' => '1',
     );
     $widget_settings = array();
-    $this->createFileField($field_name, $type_name, $field_settings, $instance_settings, $widget_settings);
+    $this->createFileField($field_name, 'node', $type_name, $field_settings, $instance_settings, $widget_settings);
 
     // Create a new node *without* the file field set, and check that the field
     // is not shown for each node display.
diff --git a/core/modules/file/lib/Drupal/file/Tests/FileFieldPathTest.php b/core/modules/file/lib/Drupal/file/Tests/FileFieldPathTest.php
index f2c45b6..3fa22c4 100644
--- a/core/modules/file/lib/Drupal/file/Tests/FileFieldPathTest.php
+++ b/core/modules/file/lib/Drupal/file/Tests/FileFieldPathTest.php
@@ -27,7 +27,7 @@ public static function getInfo() {
   function testUploadPath() {
     $field_name = strtolower($this->randomName());
     $type_name = 'article';
-    $this->createFileField($field_name, $type_name);
+    $this->createFileField($field_name, 'node', $type_name);
     $test_file = $this->getTestFile('text');
 
     // Create a new node.
diff --git a/core/modules/file/lib/Drupal/file/Tests/FileFieldRSSContentTest.php b/core/modules/file/lib/Drupal/file/Tests/FileFieldRSSContentTest.php
index e241dea..86364c6 100644
--- a/core/modules/file/lib/Drupal/file/Tests/FileFieldRSSContentTest.php
+++ b/core/modules/file/lib/Drupal/file/Tests/FileFieldRSSContentTest.php
@@ -43,7 +43,7 @@ function testFileFieldRSSContent() {
       'description_field' => '1',
     );
     $widget_settings = array();
-    $this->createFileField($field_name, $type_name, $field_settings, $instance_settings, $widget_settings);
+    $this->createFileField($field_name, 'node', $type_name, $field_settings, $instance_settings, $widget_settings);
 
     // RSS display must be added manually.
     $this->drupalGet("admin/structure/types/manage/$type_name/display");
diff --git a/core/modules/file/lib/Drupal/file/Tests/FileFieldRevisionTest.php b/core/modules/file/lib/Drupal/file/Tests/FileFieldRevisionTest.php
index bfe2414..65c627c 100644
--- a/core/modules/file/lib/Drupal/file/Tests/FileFieldRevisionTest.php
+++ b/core/modules/file/lib/Drupal/file/Tests/FileFieldRevisionTest.php
@@ -35,10 +35,9 @@ public static function getInfo() {
   function testRevisions() {
     $type_name = 'article';
     $field_name = strtolower($this->randomName());
-    $this->createFileField($field_name, $type_name);
-
-    // Attach the same fields to users.
-    $this->attachFileField($field_name, 'user', 'user');
+    $this->createFileField($field_name, 'node', $type_name);
+    // Create the same fields for users.
+    $this->createFileField($field_name, 'user', 'user');
 
     $test_file = $this->getTestFile('text');
 
diff --git a/core/modules/file/lib/Drupal/file/Tests/FileFieldTestBase.php b/core/modules/file/lib/Drupal/file/Tests/FileFieldTestBase.php
index 965c44d..6004852 100644
--- a/core/modules/file/lib/Drupal/file/Tests/FileFieldTestBase.php
+++ b/core/modules/file/lib/Drupal/file/Tests/FileFieldTestBase.php
@@ -57,8 +57,10 @@ function getLastFileId() {
    *
    * @param $name
    *   The name of the new field (all lowercase), exclude the "field_" prefix.
-   * @param $type_name
-   *   The node type that this field will be added to.
+   * @param $entity_type
+   *   The entity type.
+   * @param $bundle
+   *   The bundle that this field will be added to.
    * @param $field_settings
    *   A list of field settings that will be added to the defaults.
    * @param $instance_settings
@@ -66,9 +68,10 @@ function getLastFileId() {
    * @param $widget_settings
    *   A list of widget settings that will be added to the widget defaults.
    */
-  function createFileField($name, $type_name, $field_settings = array(), $instance_settings = array(), $widget_settings = array()) {
+  function createFileField($name, $entity_type, $bundle, $field_settings = array(), $instance_settings = array(), $widget_settings = array()) {
     $field_definition = array(
-      'field_name' => $name,
+      'entity_type' => $entity_type,
+      'name' => $name,
       'type' => 'file',
       'settings' => array(),
       'cardinality' => !empty($field_settings['cardinality']) ? $field_settings['cardinality'] : 1,
@@ -77,7 +80,7 @@ function createFileField($name, $type_name, $field_settings = array(), $instance
     $field = entity_create('field_entity', $field_definition);
     $field->save();
 
-    $this->attachFileField($name, 'node', $type_name, $instance_settings, $widget_settings);
+    $this->attachFileField($name, $entity_type, $bundle, $instance_settings, $widget_settings);
     return $field;
   }
 
@@ -159,7 +162,7 @@ function uploadNodeFile($file, $field_name, $nid_or_type, $new_revision = TRUE,
     }
 
     // Attach a file to the node.
-    $field = field_info_field($field_name);
+    $field = field_info_field('node', $field_name);
     $name = 'files[' . $field_name . '_' . $langcode . '_0]';
     if ($field['cardinality'] != 1) {
       $name .= '[]';
diff --git a/core/modules/file/lib/Drupal/file/Tests/FileFieldValidateTest.php b/core/modules/file/lib/Drupal/file/Tests/FileFieldValidateTest.php
index a7cf1e5..670ce91 100644
--- a/core/modules/file/lib/Drupal/file/Tests/FileFieldValidateTest.php
+++ b/core/modules/file/lib/Drupal/file/Tests/FileFieldValidateTest.php
@@ -30,8 +30,8 @@ public static function getInfo() {
   function testRequired() {
     $type_name = 'article';
     $field_name = strtolower($this->randomName());
-    $field = $this->createFileField($field_name, $type_name, array(), array('required' => '1'));
-    $instance = field_info_instance('node', $field_name, $type_name);
+    $field = $this->createFileField($field_name, 'node', $type_name, array(), array('required' => '1'));
+    $instance = field_info_instance($field_name, 'node', $type_name);
 
     $test_file = $this->getTestFile('text');
 
@@ -53,7 +53,7 @@ function testRequired() {
 
     // Try again with a multiple value field.
     $field->delete();
-    $this->createFileField($field_name, $type_name, array('cardinality' => FIELD_CARDINALITY_UNLIMITED), array('required' => '1'));
+    $this->createFileField($field_name, 'node', $type_name, array('cardinality' => FIELD_CARDINALITY_UNLIMITED), array('required' => '1'));
 
     // Try to post a new node without uploading a file in the multivalue field.
     $edit = array('title' => $this->randomName());
@@ -74,7 +74,7 @@ function testRequired() {
   function testFileMaxSize() {
     $type_name = 'article';
     $field_name = strtolower($this->randomName());
-    $this->createFileField($field_name, $type_name, array(), array('required' => '1'));
+    $this->createFileField($field_name, 'node', $type_name, array(), array('required' => '1'));
 
     $small_file = $this->getTestFile('text', 131072); // 128KB.
     $large_file = $this->getTestFile('text', 1310720); // 1.2MB
@@ -120,7 +120,7 @@ function testFileMaxSize() {
   function testFileExtension() {
     $type_name = 'article';
     $field_name = strtolower($this->randomName());
-    $this->createFileField($field_name, $type_name);
+    $this->createFileField($field_name, 'node', $type_name);
 
     $test_file = $this->getTestFile('image');
     list(, $test_file_extension) = explode('.', $test_file->getFilename());
diff --git a/core/modules/file/lib/Drupal/file/Tests/FileFieldWidgetTest.php b/core/modules/file/lib/Drupal/file/Tests/FileFieldWidgetTest.php
index 2267b1a..7676db2 100644
--- a/core/modules/file/lib/Drupal/file/Tests/FileFieldWidgetTest.php
+++ b/core/modules/file/lib/Drupal/file/Tests/FileFieldWidgetTest.php
@@ -35,7 +35,7 @@ public static function getInfo() {
   function testSingleValuedWidget() {
     $type_name = 'article';
     $field_name = strtolower($this->randomName());
-    $this->createFileField($field_name, $type_name);
+    $this->createFileField($field_name, 'node', $type_name);
 
     $test_file = $this->getTestFile('text');
 
@@ -96,8 +96,8 @@ function testMultiValuedWidget() {
     // names).
     $field_name = 'test_file_field_1';
     $field_name2 = 'test_file_field_2';
-    $this->createFileField($field_name, $type_name, array('cardinality' => 3));
-    $this->createFileField($field_name2, $type_name, array('cardinality' => 3));
+    $this->createFileField($field_name, 'node', $type_name, array('cardinality' => 3));
+    $this->createFileField($field_name2, 'node', $type_name, array('cardinality' => 3));
 
     $test_file = $this->getTestFile('text');
 
@@ -206,8 +206,8 @@ function testMultiValuedWidget() {
   function testPrivateFileSetting() {
     $type_name = 'article';
     $field_name = strtolower($this->randomName());
-    $this->createFileField($field_name, $type_name);
-    $instance = field_info_instance('node', $field_name, $type_name);
+    $this->createFileField($field_name, 'node', $type_name);
+    $instance = field_info_instance($field_name, 'node', $type_name);
 
     $test_file = $this->getTestFile('text');
 
@@ -315,7 +315,7 @@ function testPrivateFileComment() {
   function testWidgetValidation() {
     $type_name = 'article';
     $field_name = strtolower($this->randomName());
-    $this->createFileField($field_name, $type_name);
+    $this->createFileField($field_name, 'node', $type_name);
     $this->updateFileField($field_name, $type_name, array('file_extensions' => 'txt'));
 
     foreach (array('nojs', 'js') as $type) {
@@ -325,7 +325,7 @@ function testWidgetValidation() {
       $this->drupalGet("node/$nid/edit");
       $test_file_text = $this->getTestFile('text');
       $test_file_image = $this->getTestFile('image');
-      $field = field_info_field($field_name);
+      $field = field_info_field('ndde', $field_name);
       $name = 'files[' . $field_name . '_' . Language::LANGCODE_NOT_SPECIFIED . '_0]';
 
       // Upload file with incorrect extension, check for validation error.
diff --git a/core/modules/file/lib/Drupal/file/Tests/FileItemTest.php b/core/modules/file/lib/Drupal/file/Tests/FileItemTest.php
index fd00c11..f44e48d 100644
--- a/core/modules/file/lib/Drupal/file/Tests/FileItemTest.php
+++ b/core/modules/file/lib/Drupal/file/Tests/FileItemTest.php
@@ -45,7 +45,8 @@ public function setUp() {
     $this->installSchema('file', 'file_usage');
 
     entity_create('field_entity', array(
-      'field_name' => 'file_test',
+      'name' => 'file_test',
+      'entity_type' => 'entity_test',
       'type' => 'file',
       'cardinality' => FIELD_CARDINALITY_UNLIMITED,
     ))->save();
diff --git a/core/modules/file/lib/Drupal/file/Tests/FilePrivateTest.php b/core/modules/file/lib/Drupal/file/Tests/FilePrivateTest.php
index 1b8a82f..bf338e0 100644
--- a/core/modules/file/lib/Drupal/file/Tests/FilePrivateTest.php
+++ b/core/modules/file/lib/Drupal/file/Tests/FilePrivateTest.php
@@ -41,11 +41,11 @@ public function setUp() {
   function testPrivateFile() {
     $type_name = 'article';
     $field_name = strtolower($this->randomName());
-    $this->createFileField($field_name, $type_name, array('uri_scheme' => 'private'));
+    $this->createFileField($field_name, 'node', $type_name, array('uri_scheme' => 'private'));
 
     // Create a field with no view access - see field_test_field_access().
     $no_access_field_name = 'field_no_view_access';
-    $this->createFileField($no_access_field_name, $type_name, array('uri_scheme' => 'private'));
+    $this->createFileField($no_access_field_name, 'node', $type_name, array('uri_scheme' => 'private'));
 
     $test_file = $this->getTestFile('text');
     $nid = $this->uploadNodeFile($test_file, $field_name, $type_name, TRUE, array('private' => TRUE));
diff --git a/core/modules/file/lib/Drupal/file/Tests/FileTokenReplaceTest.php b/core/modules/file/lib/Drupal/file/Tests/FileTokenReplaceTest.php
index 36d323d..b9ba145 100644
--- a/core/modules/file/lib/Drupal/file/Tests/FileTokenReplaceTest.php
+++ b/core/modules/file/lib/Drupal/file/Tests/FileTokenReplaceTest.php
@@ -35,7 +35,7 @@ function testFileTokenReplacement() {
     // Create file field.
     $type_name = 'article';
     $field_name = 'field_' . strtolower($this->randomName());
-    $this->createFileField($field_name, $type_name);
+    $this->createFileField($field_name, 'node', $type_name);
 
     $test_file = $this->getTestFile('text');
     // Coping a file to test uploads with non-latin filenames.
diff --git a/core/modules/forum/forum.install b/core/modules/forum/forum.install
index d44da5c..d1bc98b 100644
--- a/core/modules/forum/forum.install
+++ b/core/modules/forum/forum.install
@@ -55,6 +55,7 @@ function forum_enable() {
     entity_create('field_entity', array(
       'field_name' => 'taxonomy_forums',
       'type' => 'taxonomy_term_reference',
+      'entity_type' => 'node',
       'settings' => array(
         'allowed_values' => array(
           array(
@@ -114,7 +115,7 @@ function forum_uninstall() {
   // Load the dependent Taxonomy module, in case it has been disabled.
   drupal_load('module', 'taxonomy');
 
-  if ($field = field_info_field('taxonomy_forums')) {
+  if ($field = field_info_field('node', 'taxonomy_forums')) {
     $field->delete();
   }
 
diff --git a/core/modules/forum/forum.module b/core/modules/forum/forum.module
index 18dd4e9..42100a9 100644
--- a/core/modules/forum/forum.module
+++ b/core/modules/forum/forum.module
@@ -185,7 +185,7 @@ function forum_menu_local_tasks(&$data, $router_item, $root_path) {
     if ($forum_term) {
       $links = array();
       // Loop through all bundles for forum taxonomy vocabulary field.
-      $field = field_info_field('taxonomy_forums');
+      $field = field_info_field('node', 'taxonomy_forums');
       foreach ($field['bundles']['node'] as $type_name) {
         if (($type = entity_load('node_type', $type_name)) && node_access('create', $type_name)) {
           $links[$type_name] = array(
@@ -505,7 +505,7 @@ function forum_comment_delete($comment) {
 /**
  * Implements hook_field_storage_pre_insert().
  */
-function forum_field_storage_pre_insert(EntityInterface $entity, &$skip_fields) {
+function forum_field_storage_pre_insert(EntityInterface $entity) {
   if ($entity->entityType() == 'node' && $entity->status && _forum_node_check_node_type($entity)) {
     $query = db_insert('forum_index')->fields(array('nid', 'title', 'tid', 'sticky', 'created', 'comment_count', 'last_comment_timestamp'));
     foreach ($entity->getTranslationLanguages() as $langcode => $language) {
@@ -527,7 +527,7 @@ function forum_field_storage_pre_insert(EntityInterface $entity, &$skip_fields)
 /**
  * Implements hook_field_storage_pre_update().
  */
-function forum_field_storage_pre_update(EntityInterface $entity, &$skip_fields) {
+function forum_field_storage_pre_update(EntityInterface $entity) {
   $first_call = &drupal_static(__FUNCTION__, array());
 
   if ($entity->entityType() == 'node' && _forum_node_check_node_type($entity)) {
diff --git a/core/modules/forum/lib/Drupal/forum/Tests/ForumUninstallTest.php b/core/modules/forum/lib/Drupal/forum/Tests/ForumUninstallTest.php
index 0fe25e3..cce8db0 100644
--- a/core/modules/forum/lib/Drupal/forum/Tests/ForumUninstallTest.php
+++ b/core/modules/forum/lib/Drupal/forum/Tests/ForumUninstallTest.php
@@ -34,7 +34,7 @@ public static function getInfo() {
    */
   function testForumUninstallWithField() {
     // Ensure that the field exists before uninstallation.
-    $field = field_info_field('taxonomy_forums');
+    $field = field_info_field('node', 'taxonomy_forums');
     $this->assertNotNull($field, 'The taxonomy_forums field exists.');
 
     // Uninstall the forum module which should trigger field deletion.
@@ -42,7 +42,7 @@ function testForumUninstallWithField() {
     $this->container->get('module_handler')->uninstall(array('forum'));
 
     // Check that the field is now deleted.
-    $field = field_info_field('taxonomy_forums');
+    $field = field_info_field('node', 'taxonomy_forums');
     $this->assertNull($field, 'The taxonomy_forums field has been deleted.');
   }
 
@@ -52,12 +52,12 @@ function testForumUninstallWithField() {
    */
   function testForumUninstallWithoutField() {
     // Manually delete the taxonomy_forums field before module uninstallation.
-    $field = field_info_field('taxonomy_forums');
+    $field = field_info_field('node', 'taxonomy_forums');
     $this->assertNotNull($field, 'The taxonomy_forums field exists.');
     $field->delete();
 
     // Check that the field is now deleted.
-    $field = field_info_field('taxonomy_forums');
+    $field = field_info_field('node', 'taxonomy_forums');
     $this->assertNull($field, 'The taxonomy_forums field has been deleted.');
 
     // Ensure that uninstallation succeeds even if the field has already been
diff --git a/core/modules/hal/lib/Drupal/hal/Tests/NormalizerTestBase.php b/core/modules/hal/lib/Drupal/hal/Tests/NormalizerTestBase.php
index ea55fd9..c37f152 100644
--- a/core/modules/hal/lib/Drupal/hal/Tests/NormalizerTestBase.php
+++ b/core/modules/hal/lib/Drupal/hal/Tests/NormalizerTestBase.php
@@ -78,7 +78,8 @@ function setUp() {
 
     // Create the test text field.
     entity_create('field_entity', array(
-      'field_name' => 'field_test_text',
+      'name' => 'field_test_text',
+      'entity_type' => 'entity_test',
       'type' => 'text',
       'translatable' => FALSE,
     ))->save();
@@ -90,7 +91,8 @@ function setUp() {
 
     // Create the test translatable field.
     entity_create('field_entity', array(
-      'field_name' => 'field_test_translatable_text',
+      'name' => 'field_test_translatable_text',
+      'entity_type' => 'entity_test',
       'type' => 'text',
       'translatable' => TRUE,
     ))->save();
@@ -106,7 +108,8 @@ function setUp() {
       'settings' => array(
         'target_type' => 'entity_test',
       ),
-      'field_name' => 'field_test_entity_reference',
+      'name' => 'field_test_entity_reference',
+      'entity_type' => 'entity_test',
       'type' => 'entity_reference',
     ))->save();
     entity_create('field_instance', array(
diff --git a/core/modules/image/image.views.inc b/core/modules/image/image.views.inc
index 2e70c08..2d244ff 100644
--- a/core/modules/image/image.views.inc
+++ b/core/modules/image/image.views.inc
@@ -6,6 +6,7 @@
  *
  * @ingroup views_module_handlers
  */
+use Drupal\Core\Entity\DatabaseStorageController;
 
 /**
  * Implements hook_field_views_data().
@@ -15,8 +16,8 @@
  *
  * @see field_views_field_default_views_data()
  */
-function image_field_views_data($field) {
-  $data = field_views_field_default_views_data($field);
+function image_field_views_data($field, $sql_entity_types) {
+  $data = field_views_field_default_views_data($field, $sql_entity_types);
   foreach ($data as $table_name => $table_data) {
     // Add the relationship only on the target_id field.
     $data[$table_name][$field['field_name'] . '_target_id']['relationship'] = array(
@@ -35,8 +36,8 @@ function image_field_views_data($field) {
  *
  * Views integration to provide reverse relationships on image fields.
  */
-function image_field_views_data_views_data_alter(&$data, $field) {
-  foreach ($field['bundles'] as $entity_type => $bundles) {
+function image_field_views_data_views_data_alter(&$data, $field, $sql_entity_types) {
+  foreach ($sql_entity_types as $entity_type) {
     $entity_info = entity_get_info($entity_type);
     $pseudo_field_name = 'reverse_' . $field['field_name'] . '_' . $entity_type;
 
@@ -51,7 +52,7 @@ function image_field_views_data_views_data_alter(&$data, $field) {
       'help' => t('Relate each @entity with a @field set to the image.', array('@entity' => $entity, '@field' => $label)),
       'id' => 'entity_reverse',
       'field_name' => $field['field_name'],
-      'field table' => _field_sql_storage_tablename($field),
+      'field table' => DatabaseStorageController::_fieldTableName($field),
       'field field' => $field['field_name'] . '_target_id',
       'base' => $entity_info['base_table'],
       'base field' => $entity_info['entity_keys']['id'],
diff --git a/core/modules/image/lib/Drupal/image/Tests/ImageFieldDefaultImagesTest.php b/core/modules/image/lib/Drupal/image/Tests/ImageFieldDefaultImagesTest.php
index 164cbad..3652b46 100644
--- a/core/modules/image/lib/Drupal/image/Tests/ImageFieldDefaultImagesTest.php
+++ b/core/modules/image/lib/Drupal/image/Tests/ImageFieldDefaultImagesTest.php
@@ -52,11 +52,11 @@ function testDefaultImages() {
       'preview_image_style' => 'medium',
     );
     $instance = $this->createImageField($field_name, 'article', $field_settings, $instance_settings, $widget_settings);
-    $field = field_info_field($field_name);
+    $field = field_info_field('node', $field_name);
 
     // Add another instance with another default image to the page content type.
     $instance2 = entity_create('field_instance', array(
-      'field_name' => $field->id(),
+      'field_name' => $field->getFieldName(),
       'entity_type' => 'node',
       'bundle' => 'page',
       'label' => $instance->label(),
@@ -69,10 +69,10 @@ function testDefaultImages() {
 
     $widget_settings = entity_get_form_display($instance['entity_type'], $instance['bundle'], 'default')->getComponent($field['field_name']);
     entity_get_form_display('node', 'page', 'default')
-      ->setComponent($field->id(), $widget_settings)
+      ->setComponent($field->getFieldName(), $widget_settings)
       ->save();
     entity_get_display('node', 'page', 'default')
-      ->setComponent($field->id())
+      ->setComponent($field->getFieldName())
       ->save();
 
     // Confirm the defaults are present on the article field settings form.
diff --git a/core/modules/image/lib/Drupal/image/Tests/ImageFieldDisplayTest.php b/core/modules/image/lib/Drupal/image/Tests/ImageFieldDisplayTest.php
index e7775ad..8639223 100644
--- a/core/modules/image/lib/Drupal/image/Tests/ImageFieldDisplayTest.php
+++ b/core/modules/image/lib/Drupal/image/Tests/ImageFieldDisplayTest.php
@@ -231,7 +231,7 @@ function testImageFieldDefaultImage() {
     $this->drupalPost("admin/structure/types/manage/article/fields/node.article.$field_name/field", $edit, t('Save field settings'));
     // Clear field info cache so the new default image is detected.
     field_info_cache_clear();
-    $field = field_info_field($field_name);
+    $field = field_info_field('node', $field_name);
     $image = file_load($field['settings']['default_image']);
     $this->assertTrue($image->isPermanent(), 'The default image status is permanent.');
     $default_output = theme('image', array('uri' => $image->getFileUri()));
@@ -259,7 +259,7 @@ function testImageFieldDefaultImage() {
     $this->drupalPost("admin/structure/types/manage/article/fields/node.article.$field_name/field", $edit, t('Save field settings'));
     // Clear field info cache so the new default image is detected.
     field_info_cache_clear();
-    $field = field_info_field($field_name);
+    $field = field_info_field('node', $field_name);
     $this->assertFalse($field['settings']['default_image'], 'Default image removed from field.');
     // Create an image field that uses the private:// scheme and test that the
     // default image works as expected.
@@ -273,7 +273,7 @@ function testImageFieldDefaultImage() {
     // Clear field info cache so the new default image is detected.
     field_info_cache_clear();
 
-    $private_field = field_info_field($private_field_name);
+    $private_field = field_info_field('node', $private_field_name);
     $image = file_load($private_field['settings']['default_image']);
     $this->assertEqual('private', file_uri_scheme($image->getFileUri()), 'Default image uses private:// scheme.');
     $this->assertTrue($image->isPermanent(), 'The default image status is permanent.');
diff --git a/core/modules/image/lib/Drupal/image/Tests/ImageFieldTestBase.php b/core/modules/image/lib/Drupal/image/Tests/ImageFieldTestBase.php
index b1d1716..5719f20 100644
--- a/core/modules/image/lib/Drupal/image/Tests/ImageFieldTestBase.php
+++ b/core/modules/image/lib/Drupal/image/Tests/ImageFieldTestBase.php
@@ -70,7 +70,8 @@ function setUp() {
    */
   function createImageField($name, $type_name, $field_settings = array(), $instance_settings = array(), $widget_settings = array()) {
     $field = array(
-      'field_name' => $name,
+      'name' => $name,
+      'entity_type' => 'node',
       'type' => 'image',
       'settings' => array(),
       'cardinality' => !empty($field_settings['cardinality']) ? $field_settings['cardinality'] : 1,
@@ -80,7 +81,6 @@ function createImageField($name, $type_name, $field_settings = array(), $instanc
 
     $instance = array(
       'field_name' => $field['field_name'],
-      'entity_type' => 'node',
       'label' => $name,
       'bundle' => $type_name,
       'required' => !empty($instance_settings['required']),
diff --git a/core/modules/image/lib/Drupal/image/Tests/ImageItemTest.php b/core/modules/image/lib/Drupal/image/Tests/ImageItemTest.php
index 5e7472f..d9c4099 100644
--- a/core/modules/image/lib/Drupal/image/Tests/ImageItemTest.php
+++ b/core/modules/image/lib/Drupal/image/Tests/ImageItemTest.php
@@ -44,7 +44,8 @@ public function setUp() {
     $this->installSchema('file', array('file_managed', 'file_usage'));
 
     entity_create('field_entity', array(
-      'field_name' => 'image_test',
+      'name' => 'image_test',
+      'entity_type' => 'entity_test',
       'type' => 'image',
       'cardinality' => FIELD_CARDINALITY_UNLIMITED,
     ))->save();
diff --git a/core/modules/link/lib/Drupal/link/Tests/LinkFieldTest.php b/core/modules/link/lib/Drupal/link/Tests/LinkFieldTest.php
index b4033ff..d48f587 100644
--- a/core/modules/link/lib/Drupal/link/Tests/LinkFieldTest.php
+++ b/core/modules/link/lib/Drupal/link/Tests/LinkFieldTest.php
@@ -68,7 +68,8 @@ function testURLValidation() {
     $field_name = drupal_strtolower($this->randomName());
     // Create a field with settings to validate.
     $this->field = entity_create('field_entity', array(
-      'field_name' => $field_name,
+      'name' => $field_name,
+      'entity_type' => 'entity_test',
       'type' => 'link',
     ));
     $this->field->save();
@@ -142,7 +143,8 @@ function testLinkTitle() {
     $field_name = drupal_strtolower($this->randomName());
     // Create a field with settings to validate.
     $this->field = entity_create('field_entity', array(
-      'field_name' => $field_name,
+      'name' => $field_name,
+      'entity_type' => 'entity_test',
       'type' => 'link',
     ));
     $this->field->save();
@@ -261,7 +263,8 @@ function testLinkFormatter() {
     $field_name = drupal_strtolower($this->randomName());
     // Create a field with settings to validate.
     $this->field = entity_create('field_entity', array(
-      'field_name' => $field_name,
+      'name' => $field_name,
+      'entity_type' => 'entity_test',
       'type' => 'link',
       'cardinality' => 2,
     ));
@@ -404,7 +407,8 @@ function testLinkSeparateFormatter() {
     $field_name = drupal_strtolower($this->randomName());
     // Create a field with settings to validate.
     $this->field = entity_create('field_entity', array(
-      'field_name' => $field_name,
+      'name' => $field_name,
+      'entity_type' => 'entity_test',
       'type' => 'link',
       'cardinality' => 2,
     ));
diff --git a/core/modules/link/lib/Drupal/link/Tests/LinkItemTest.php b/core/modules/link/lib/Drupal/link/Tests/LinkItemTest.php
index 2cd88bc..a42d6a2 100644
--- a/core/modules/link/lib/Drupal/link/Tests/LinkItemTest.php
+++ b/core/modules/link/lib/Drupal/link/Tests/LinkItemTest.php
@@ -36,7 +36,8 @@ public function setUp() {
 
     // Create an link field and instance for validation.
     entity_create('field_entity', array(
-      'field_name' => 'field_test',
+      'name' => 'field_test',
+      'entity_type' => 'entity_test',
       'type' => 'link',
     ))->save();
     entity_create('field_instance', array(
diff --git a/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkStorageController.php b/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkStorageController.php
index 43d54ce..7242cbe 100644
--- a/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkStorageController.php
+++ b/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkStorageController.php
@@ -11,6 +11,7 @@
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Entity\EntityStorageException;
 use Drupal\Core\Database\Connection;
+use Drupal\field\FieldInfo;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Cmf\Component\Routing\RouteProviderInterface;
 
@@ -52,11 +53,13 @@ class MenuLinkStorageController extends DatabaseStorageController implements Men
    *   An array of entity info for the entity type.
    * @param \Drupal\Core\Database\Connection $database
    *   The database connection to be used.
+   * @param \Drupal\field\FieldInfo $field_info
+   *   The field info service.
    * @param \Symfony\Cmf\Component\Routing\RouteProviderInterface $route_provider
    *   The route provider service.
    */
-  public function __construct($entity_type, array $entity_info, Connection $database, RouteProviderInterface $route_provider) {
-    parent::__construct($entity_type, $entity_info, $database);
+  public function __construct($entity_type, array $entity_info, Connection $database, FieldInfo $field_info, RouteProviderInterface $route_provider) {
+    parent::__construct($entity_type, $entity_info, $database, $field_info);
 
     $this->routeProvider = $route_provider;
 
@@ -85,6 +88,7 @@ public static function createInstance(ContainerInterface $container, $entity_typ
       $entity_type,
       $entity_info,
       $container->get('database'),
+      $container->get('field.info'),
       $container->get('router.route_provider')
     );
   }
diff --git a/core/modules/node/lib/Drupal/node/NodeStorageController.php b/core/modules/node/lib/Drupal/node/NodeStorageController.php
index c3ccc3c..0b8c515 100644
--- a/core/modules/node/lib/Drupal/node/NodeStorageController.php
+++ b/core/modules/node/lib/Drupal/node/NodeStorageController.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Entity\DatabaseStorageControllerNG;
 use Drupal\Core\Entity\EntityInterface;
+use Symfony\Component\DependencyInjection\Container;
 
 /**
  * Controller class for nodes.
@@ -46,10 +47,10 @@ protected function attachLoad(&$queried_entities, $load_revision = FALSE) {
     }
 
     if ($load_revision) {
-      field_attach_load_revision($this->entityType, $queried_entities);
+      $this->fieldLoad($queried_entities, FIELD_LOAD_REVISION);
     }
     else {
-      field_attach_load($this->entityType, $queried_entities);
+      $this->fieldLoad($queried_entities, FIELD_LOAD_CURRENT);
     }
 
     // Besides the list of nodes, pass one additional argument to
@@ -80,14 +81,9 @@ protected function invokeHook($hook, EntityInterface $node) {
     // Inline parent::invokeHook() to pass on BC-entities to node-specific
     // hooks.
 
-    $function = 'field_attach_' . $hook;
-    // @todo: field_attach_delete_revision() is named the wrong way round,
-    // consider renaming it.
-    if ($function == 'field_attach_revision_delete') {
-      $function = 'field_attach_delete_revision';
-    }
-    if (!empty($this->entityInfo['fieldable']) && function_exists($function)) {
-      $function($node);
+    $method = Container::camelize('field_' . $hook);
+    if (!empty($this->entityInfo['fieldable']) && method_exists($this, $method)) {
+      $this->$method($node);
     }
 
     // Invoke the hook.
diff --git a/core/modules/node/lib/Drupal/node/Tests/MultiStepNodeFormBasicOptionsTest.php b/core/modules/node/lib/Drupal/node/Tests/MultiStepNodeFormBasicOptionsTest.php
index 65e3aec..4fc3f7b 100644
--- a/core/modules/node/lib/Drupal/node/Tests/MultiStepNodeFormBasicOptionsTest.php
+++ b/core/modules/node/lib/Drupal/node/Tests/MultiStepNodeFormBasicOptionsTest.php
@@ -41,7 +41,8 @@ function testMultiStepNodeFormBasicOptions() {
     // Create an unlimited cardinality field.
     $this->field_name = drupal_strtolower($this->randomName());
     entity_create('field_entity', array(
-      'field_name' => $this->field_name,
+      'name' => $this->field_name,
+      'entity_type' => 'node',
       'type' => 'text',
       'cardinality' => -1,
     ))->save();
diff --git a/core/modules/node/lib/Drupal/node/Tests/NodeAccessFieldTest.php b/core/modules/node/lib/Drupal/node/Tests/NodeAccessFieldTest.php
index e1a33aa..3cc22a5 100644
--- a/core/modules/node/lib/Drupal/node/Tests/NodeAccessFieldTest.php
+++ b/core/modules/node/lib/Drupal/node/Tests/NodeAccessFieldTest.php
@@ -62,7 +62,8 @@ public function setUp() {
     // Add a custom field to the page content type.
     $this->field_name = drupal_strtolower($this->randomName() . '_field_name');
     entity_create('field_entity', array(
-      'field_name' => $this->field_name,
+      'name' => $this->field_name,
+      'entity_type' => 'node',
       'type' => 'text'
     ))->save();
     entity_create('field_instance', array(
diff --git a/core/modules/node/lib/Drupal/node/Tests/NodeFieldMultilingualTestCase.php b/core/modules/node/lib/Drupal/node/Tests/NodeFieldMultilingualTestCase.php
index cbf3a29..7e42250 100644
--- a/core/modules/node/lib/Drupal/node/Tests/NodeFieldMultilingualTestCase.php
+++ b/core/modules/node/lib/Drupal/node/Tests/NodeFieldMultilingualTestCase.php
@@ -59,7 +59,7 @@ function setUp() {
     $this->assertRaw(t('The content type %type has been updated.', array('%type' => 'Basic page')), 'Basic page content type has been updated.');
 
     // Make node body translatable.
-    $field = field_info_field('body');
+    $field = field_info_field('node', 'body');
     $field->translatable = TRUE;
     $field->save();
   }
diff --git a/core/modules/node/lib/Drupal/node/Tests/NodeTranslationUITest.php b/core/modules/node/lib/Drupal/node/Tests/NodeTranslationUITest.php
index 473947b..db5747a 100644
--- a/core/modules/node/lib/Drupal/node/Tests/NodeTranslationUITest.php
+++ b/core/modules/node/lib/Drupal/node/Tests/NodeTranslationUITest.php
@@ -169,7 +169,7 @@ function testFieldTranslationForm() {
     $this->assertRaw('Not translated');
 
     // Delete the only translatable field.
-    field_info_field('field_test_et_ui_test')->delete();
+    field_info_field($this->entityType, 'field_test_et_ui_test')->delete();
 
     // Visit translation page.
     $this->drupalGet('node/' . $article->nid . '/translations');
diff --git a/core/modules/node/lib/Drupal/node/Tests/PagePreviewTest.php b/core/modules/node/lib/Drupal/node/Tests/PagePreviewTest.php
index b485545..86f3f37 100644
--- a/core/modules/node/lib/Drupal/node/Tests/PagePreviewTest.php
+++ b/core/modules/node/lib/Drupal/node/Tests/PagePreviewTest.php
@@ -68,7 +68,8 @@ function setUp() {
     // Set up a field and instance.
     $this->field_name = drupal_strtolower($this->randomName());
     entity_create('field_entity', array(
-      'field_name' => $this->field_name,
+      'name' => $this->field_name,
+      'entity_type' => 'node',
       'type' => 'taxonomy_term_reference',
       'settings' => array(
         'allowed_values' => array(
diff --git a/core/modules/node/node.module b/core/modules/node/node.module
index 293c64e..b1c7f14 100644
--- a/core/modules/node/node.module
+++ b/core/modules/node/node.module
@@ -395,13 +395,13 @@ function node_type_load($name) {
  */
 function node_add_body_field(NodeTypeInterface $type, $label = 'Body') {
    // Add or remove the body field, as needed.
-  $field = field_info_field('body');
+  $field = field_info_field('node', 'body');
   $instance = field_info_instance('node', 'body', $type->id());
   if (empty($field)) {
     $field = entity_create('field_entity', array(
-      'field_name' => 'body',
+      'name' => 'body',
+      'entity_type' => 'node',
       'type' => 'text_with_summary',
-      'entity_types' => array('node'),
     ));
     $field->save();
   }
@@ -417,20 +417,20 @@ function node_add_body_field(NodeTypeInterface $type, $label = 'Body') {
 
     // Assign widget settings for the 'default' form mode.
     entity_get_form_display('node', $type->type, 'default')
-      ->setComponent($field->id(), array(
+      ->setComponent($field->getFieldName(), array(
         'type' => 'text_textarea_with_summary',
       ))
       ->save();
 
     // Assign display settings for the 'default' and 'teaser' view modes.
     entity_get_display('node', $type->type, 'default')
-      ->setComponent($field->id(), array(
+      ->setComponent($field->getFieldName(), array(
         'label' => 'hidden',
         'type' => 'text_default',
       ))
       ->save();
     entity_get_display('node', $type->type, 'teaser')
-      ->setComponent($field->id(), array(
+      ->setComponent($field->getFieldName(), array(
         'label' => 'hidden',
         'type' => 'text_summary_or_trimmed',
       ))
diff --git a/core/modules/node/tests/modules/node_access_test_language/node_access_test_language.module b/core/modules/node/tests/modules/node_access_test_language/node_access_test_language.module
index 1baa48e..f5a5ede 100644
--- a/core/modules/node/tests/modules/node_access_test_language/node_access_test_language.module
+++ b/core/modules/node/tests/modules/node_access_test_language/node_access_test_language.module
@@ -50,7 +50,8 @@ function node_access_test_language_node_access_records(EntityInterface $node) {
  */
 function node_access_test_language_enable() {
   $field_private = entity_create('field_entity', array(
-    'field_name' => 'field_private',
+    'name' => 'field_private',
+    'entity_type' => 'node',
     'type' => 'list_boolean',
     'cardinality' => 1,
     'translatable'  => TRUE,
diff --git a/core/modules/number/lib/Drupal/number/Tests/NumberFieldTest.php b/core/modules/number/lib/Drupal/number/Tests/NumberFieldTest.php
index 8bea406..8cc9cd3 100644
--- a/core/modules/number/lib/Drupal/number/Tests/NumberFieldTest.php
+++ b/core/modules/number/lib/Drupal/number/Tests/NumberFieldTest.php
@@ -64,7 +64,8 @@ function setUp() {
   function testNumberDecimalField() {
     // Create a field with settings to validate.
     $this->field = entity_create('field_entity', array(
-      'field_name' => drupal_strtolower($this->randomName()),
+      'name' => drupal_strtolower($this->randomName()),
+      'entity_type' => 'entity_test',
       'type' => 'number_decimal',
       'settings' => array(
         'precision' => 8, 'scale' => 4, 'decimal_separator' => '.',
diff --git a/core/modules/number/lib/Drupal/number/Tests/NumberItemTest.php b/core/modules/number/lib/Drupal/number/Tests/NumberItemTest.php
index a0cc904..636c55d 100644
--- a/core/modules/number/lib/Drupal/number/Tests/NumberItemTest.php
+++ b/core/modules/number/lib/Drupal/number/Tests/NumberItemTest.php
@@ -37,7 +37,8 @@ public function setUp() {
     // Create number fields and instances for validation.
     foreach (array('integer', 'float', 'decimal') as $type) {
       entity_create('field_entity', array(
-        'field_name' => 'field_' . $type,
+        'name' => 'field_' . $type,
+        'entity_type' => 'entity_test',
         'type' => 'number_' . $type,
       ))->save();
       entity_create('field_instance', array(
diff --git a/core/modules/options/lib/Drupal/options/Tests/OptionsDynamicValuesTest.php b/core/modules/options/lib/Drupal/options/Tests/OptionsDynamicValuesTest.php
index c270e4a..6607332 100644
--- a/core/modules/options/lib/Drupal/options/Tests/OptionsDynamicValuesTest.php
+++ b/core/modules/options/lib/Drupal/options/Tests/OptionsDynamicValuesTest.php
@@ -33,7 +33,8 @@ function setUp() {
 
     $this->field_name = 'test_options';
     entity_create('field_entity', array(
-      'field_name' => $this->field_name,
+      'name' => $this->field_name,
+      'entity_type' => 'entity_test_rev',
       'type' => 'list_text',
       'cardinality' => 1,
       'settings' => array(
diff --git a/core/modules/options/lib/Drupal/options/Tests/OptionsFieldUITest.php b/core/modules/options/lib/Drupal/options/Tests/OptionsFieldUITest.php
index d34f178..38f5c34 100644
--- a/core/modules/options/lib/Drupal/options/Tests/OptionsFieldUITest.php
+++ b/core/modules/options/lib/Drupal/options/Tests/OptionsFieldUITest.php
@@ -231,7 +231,7 @@ function testOptionsAllowedValuesBoolean() {
     $this->drupalGet($this->admin_path);
     $this->assertFieldByName('on', $on, t("The 'On' value is stored correctly."));
     $this->assertFieldByName('off', $off, t("The 'Off' value is stored correctly."));
-    $field = field_info_field($this->field_name);
+    $field = field_info_field('node', $this->field_name);
     $this->assertEqual($field['settings']['allowed_values'], $allowed_values, 'The allowed value is correct');
     $this->assertFalse(isset($field['settings']['on']), 'The on value is not saved into settings');
     $this->assertFalse(isset($field['settings']['off']), 'The off value is not saved into settings');
@@ -259,7 +259,8 @@ function testOptionsTrimmedValuesText() {
   protected function createOptionsField($type) {
     // Create a test field and instance.
     entity_create('field_entity', array(
-      'field_name' => $this->field_name,
+      'name' => $this->field_name,
+      'entity_type' => 'node',
       'type' => $type,
     ))->save();
     entity_create('field_instance', array(
@@ -294,7 +295,7 @@ function assertAllowedValuesInput($input_string, $result, $message) {
     }
     else {
       field_info_cache_clear();
-      $field = field_info_field($this->field_name);
+      $field = field_info_field('node', $this->field_name);
       $this->assertIdentical($field['settings']['allowed_values'], $result, $message);
     }
   }
diff --git a/core/modules/options/lib/Drupal/options/Tests/OptionsFieldUnitTestBase.php b/core/modules/options/lib/Drupal/options/Tests/OptionsFieldUnitTestBase.php
index 748ee6e..dc987d4 100644
--- a/core/modules/options/lib/Drupal/options/Tests/OptionsFieldUnitTestBase.php
+++ b/core/modules/options/lib/Drupal/options/Tests/OptionsFieldUnitTestBase.php
@@ -58,7 +58,8 @@ public function setUp() {
     $this->installSchema('system', 'menu_router');
 
     $this->fieldDefinition = array(
-      'field_name' => $this->fieldName,
+      'name' => $this->fieldName,
+      'entity_type' => 'entity_test',
       'type' => 'list_integer',
       'cardinality' => 1,
       'settings' => array(
diff --git a/core/modules/options/lib/Drupal/options/Tests/OptionsWidgetsTest.php b/core/modules/options/lib/Drupal/options/Tests/OptionsWidgetsTest.php
index dbc1876..ef20de5 100644
--- a/core/modules/options/lib/Drupal/options/Tests/OptionsWidgetsTest.php
+++ b/core/modules/options/lib/Drupal/options/Tests/OptionsWidgetsTest.php
@@ -64,7 +64,8 @@ function setUp() {
 
     // Field with cardinality 1.
     $this->card_1 = entity_create('field_entity', array(
-      'field_name' => 'card_1',
+      'name' => 'card_1',
+      'entity_type' => 'entity_test',
       'type' => 'list_integer',
       'cardinality' => 1,
       'settings' => array(
@@ -76,7 +77,8 @@ function setUp() {
 
     // Field with cardinality 2.
     $this->card_2 = entity_create('field_entity', array(
-      'field_name' => 'card_2',
+      'name' => 'card_2',
+      'entity_type' => 'entity_test',
       'type' => 'list_integer',
       'cardinality' => 2,
       'settings' => array(
@@ -88,7 +90,8 @@ function setUp() {
 
     // Boolean field.
     $this->bool = entity_create('field_entity', array(
-      'field_name' => 'bool',
+      'name' => 'bool',
+      'entity_type' => 'entity_test',
       'type' => 'list_boolean',
       'cardinality' => 1,
       'settings' => array(
@@ -538,7 +541,7 @@ function testOnOffCheckbox() {
     $fieldUpdate['settings']['allowed_values'] = array(0 => 0, 1 => 'MyOnValue');
     $fieldUpdate->save();
     entity_create('field_instance', array(
-      'field_name' => $this->bool['field_name'],
+      'field_name' => $this->bool->id(),
       'entity_type' => 'node',
       'bundle' => 'page',
     ))->save();
diff --git a/core/modules/rdf/lib/Drupal/rdf/Tests/FileFieldAttributesTest.php b/core/modules/rdf/lib/Drupal/rdf/Tests/FileFieldAttributesTest.php
index 11176dc..46119d5 100644
--- a/core/modules/rdf/lib/Drupal/rdf/Tests/FileFieldAttributesTest.php
+++ b/core/modules/rdf/lib/Drupal/rdf/Tests/FileFieldAttributesTest.php
@@ -56,7 +56,7 @@ public function setUp() {
     $this->fieldName = strtolower($this->randomName());
 
     $type_name = 'article';
-    $this->createFileField($this->fieldName, $type_name);
+    $this->createFileField($this->fieldName, 'node', $type_name);
 
     // Set the teaser display to show this field.
     entity_get_display('node', 'article', 'teaser')
diff --git a/core/modules/rdf/lib/Drupal/rdf/Tests/TaxonomyTermFieldAttributesTest.php b/core/modules/rdf/lib/Drupal/rdf/Tests/TaxonomyTermFieldAttributesTest.php
index 78c91ca..cea3ff9 100644
--- a/core/modules/rdf/lib/Drupal/rdf/Tests/TaxonomyTermFieldAttributesTest.php
+++ b/core/modules/rdf/lib/Drupal/rdf/Tests/TaxonomyTermFieldAttributesTest.php
@@ -154,7 +154,8 @@ function testNodeTeaser() {
    */
   protected function createTaxonomyTermReferenceField($field_name, $vocabulary) {
     entity_create('field_entity', array(
-      'field_name' => $field_name,
+      'name' => $field_name,
+      'entity_type' => 'node',
       'type' => 'taxonomy_term_reference',
       'cardinality' => FIELD_CARDINALITY_UNLIMITED,
       'settings' => array(
diff --git a/core/modules/search/lib/Drupal/search/Tests/SearchMultilingualEntityTest.php b/core/modules/search/lib/Drupal/search/Tests/SearchMultilingualEntityTest.php
index 266c47d..158dd99 100644
--- a/core/modules/search/lib/Drupal/search/Tests/SearchMultilingualEntityTest.php
+++ b/core/modules/search/lib/Drupal/search/Tests/SearchMultilingualEntityTest.php
@@ -48,7 +48,7 @@ function setUp() {
 
     // Make the body field translatable.
     // The parent class has already created the article and page content types.
-    $field = field_info_field('body');
+    $field = field_info_field('node', 'body');
     $field->translatable = TRUE;
     $field->save();
 
diff --git a/core/modules/serialization/lib/Drupal/serialization/Tests/EntityResolverTest.php b/core/modules/serialization/lib/Drupal/serialization/Tests/EntityResolverTest.php
index 48d0293..5d9dac4 100644
--- a/core/modules/serialization/lib/Drupal/serialization/Tests/EntityResolverTest.php
+++ b/core/modules/serialization/lib/Drupal/serialization/Tests/EntityResolverTest.php
@@ -38,7 +38,8 @@ protected function setUp() {
       'settings' => array(
         'target_type' => 'entity_test_mulrev',
       ),
-      'field_name' => 'field_test_entity_reference',
+      'name' => 'field_test_entity_reference',
+      'entity_type' => 'entity_test_mulrev',
       'type' => 'entity_reference',
     ))->save();
 
diff --git a/core/modules/serialization/lib/Drupal/serialization/Tests/NormalizerTestBase.php b/core/modules/serialization/lib/Drupal/serialization/Tests/NormalizerTestBase.php
index 74fa8d9..8bb36f2 100644
--- a/core/modules/serialization/lib/Drupal/serialization/Tests/NormalizerTestBase.php
+++ b/core/modules/serialization/lib/Drupal/serialization/Tests/NormalizerTestBase.php
@@ -16,7 +16,7 @@
    *
    * @var array
    */
-  public static $modules = array('serialization', 'system', 'entity', 'field', 'entity_test', 'text', 'field_sql_storage');
+  public static $modules = array('serialization', 'system', 'entity', 'field', 'entity_test', 'text');
 
   protected function setUp() {
     parent::setUp();
@@ -27,7 +27,8 @@ protected function setUp() {
 
     // Auto-create a field for testing.
     entity_create('field_entity', array(
-      'field_name' => 'field_test_text',
+      'name' => 'field_test_text',
+      'entity_type' => 'entity_test_mulrev',
       'type' => 'text',
       'cardinality' => 1,
       'translatable' => FALSE,
diff --git a/core/modules/simpletest/lib/Drupal/simpletest/Tests/DrupalUnitTestBaseTest.php b/core/modules/simpletest/lib/Drupal/simpletest/Tests/DrupalUnitTestBaseTest.php
index 58da4c3..9c57d8b 100644
--- a/core/modules/simpletest/lib/Drupal/simpletest/Tests/DrupalUnitTestBaseTest.php
+++ b/core/modules/simpletest/lib/Drupal/simpletest/Tests/DrupalUnitTestBaseTest.php
@@ -232,12 +232,13 @@ function testEnableModulesFixedList() {
       'mode' => 'default',
     ));
     $field = entity_create('field_entity', array(
-      'field_name' => 'test_field',
+      'name' => 'test_field',
+      'entity_type' => 'entity_test',
       'type' => 'test_field'
     ));
     $field->save();
     entity_create('field_instance', array(
-      'field_name' => $field->id(),
+      'field_name' => $field->getFieldName(),
       'entity_type' => 'entity_test',
       'bundle' => 'entity_test',
     ))->save();
diff --git a/core/modules/system/lib/Drupal/system/Tests/Ajax/MultiFormTest.php b/core/modules/system/lib/Drupal/system/Tests/Ajax/MultiFormTest.php
index f15f382..5051384 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Ajax/MultiFormTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Ajax/MultiFormTest.php
@@ -35,7 +35,8 @@ function setUp() {
     // Create a multi-valued field for 'page' nodes to use for Ajax testing.
     $field_name = 'field_ajax_test';
     entity_create('field_entity', array(
-      'field_name' => $field_name,
+      'name' => $field_name,
+      'entity_type' => 'node',
       'type' => 'text',
       'cardinality' => FIELD_CARDINALITY_UNLIMITED,
     ))->save();
diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityQueryAggregateTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityQueryAggregateTest.php
index faa7090..7939fb0 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityQueryAggregateTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityQueryAggregateTest.php
@@ -62,7 +62,8 @@ public function setUp() {
     for ($i = 1; $i <= 2; $i++) {
       $field_name = 'field_test_' . $i;
       entity_create('field_entity', array(
-        'field_name' => $field_name,
+        'name' => $field_name,
+        'entity_type' => 'entity_test',
         'type' => 'number_integer',
         'cardinality' => 2,
       ))->save();
diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityQueryRelationshipTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityQueryRelationshipTest.php
index 90ac1da..97f140a 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityQueryRelationshipTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityQueryRelationshipTest.php
@@ -81,7 +81,8 @@ public function setUp() {
     // Second, create the field.
     $this->fieldName = strtolower($this->randomName());
     $field = array(
-      'field_name' => $this->fieldName,
+      'name' => $this->fieldName,
+      'entity_type' => 'entity_test',
       'type' => 'taxonomy_term_reference',
     );
     $field['settings']['allowed_values']['vocabulary'] = $vocabulary->id();
diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityQueryTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityQueryTest.php
index 284526f..0c8430d 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityQueryTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityQueryTest.php
@@ -63,7 +63,8 @@ function setUp() {
     $greetings = drupal_strtolower($this->randomName());
     foreach (array($figures => 'shape', $greetings => 'text') as $field_name => $field_type) {
       $field = entity_create('field_entity', array(
-        'field_name' => $field_name,
+        'name' => $field_name,
+        'entity_type' => 'entity_test_mulrev',
         'type' => $field_type,
         'cardinality' => 2,
         'translatable' => TRUE,
@@ -81,7 +82,7 @@ function setUp() {
       entity_test_create_bundle($bundle);
       foreach ($fields as $field) {
         entity_create('field_instance', array(
-          'field_name' => $field->id(),
+          'field_name' => $field->getFieldName(),
           'entity_type' => 'entity_test_mulrev',
           'bundle' => $bundle,
         ))->save();
diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityTranslationFormTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityTranslationFormTest.php
index ef6c81a..f9dc51a 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityTranslationFormTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityTranslationFormTest.php
@@ -104,10 +104,10 @@ function testEntityFormLanguage() {
     $this->assertTrue($node, 'Node found in database.');
 
     // Make body translatable.
-    $field = field_info_field('body');
+    $field = field_info_field('node', 'body');
     $field->translatable = TRUE;
     $field->save();
-    $field = field_info_field('body');
+    $field = field_info_field('node', 'body');
     $this->assertTrue($field['translatable'], 'Field body is translatable.');
 
     // Create a body translation and check the form language.
diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityTranslationTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityTranslationTest.php
index 40a7e44..7adfda3 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityTranslationTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityTranslationTest.php
@@ -51,16 +51,16 @@ function setUp() {
 
     // Create a translatable test field.
     $this->field_name = drupal_strtolower($this->randomName() . '_field_name');
-    entity_create('field_entity', array(
-      'field_name' => $this->field_name,
-      'type' => 'text',
-      'cardinality' => 4,
-      'translatable' => TRUE,
-    ))->save();
-    $this->field = field_read_field($this->field_name);
 
     // Create instance in all entity variations.
     foreach (entity_test_entity_types() as $entity_type) {
+      entity_create('field_entity', array(
+        'name' => $this->field_name,
+        'entity_type' => $entity_type,
+        'type' => 'text',
+        'cardinality' => 4,
+        'translatable' => TRUE,
+      ))->save();
       entity_create('field_instance', array(
         'field_name' => $this->field_name,
         'entity_type' => $entity_type,
diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityUnitTestBase.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityUnitTestBase.php
index 34fb4cc..d848bcf 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityUnitTestBase.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityUnitTestBase.php
@@ -20,7 +20,7 @@
    *
    * @var array
    */
-  public static $modules = array('entity', 'user', 'system', 'field', 'text', 'field_sql_storage', 'entity_test');
+  public static $modules = array('entity', 'user', 'system', 'field', 'text', 'entity_test');
 
   /**
    * The entity manager service.
diff --git a/core/modules/system/lib/Drupal/system/Tests/Form/ArbitraryRebuildTest.php b/core/modules/system/lib/Drupal/system/Tests/Form/ArbitraryRebuildTest.php
index cc6546a..193c2d2 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Form/ArbitraryRebuildTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Form/ArbitraryRebuildTest.php
@@ -34,7 +34,8 @@ function setUp() {
 
     // Auto-create a field for testing.
     entity_create('field_entity', array(
-      'field_name' => 'test_multiple',
+      'name' => 'test_multiple',
+      'entity_type' => 'user',
       'type' => 'text',
       'cardinality' => -1,
       'translatable' => FALSE,
diff --git a/core/modules/system/lib/Drupal/system/Tests/Form/RebuildTest.php b/core/modules/system/lib/Drupal/system/Tests/Form/RebuildTest.php
index c580e88..460e0ca 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Form/RebuildTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Form/RebuildTest.php
@@ -72,7 +72,8 @@ function testPreserveFormActionAfterAJAX() {
     // Create a multi-valued field for 'page' nodes to use for Ajax testing.
     $field_name = 'field_ajax_test';
     $field = array(
-      'field_name' => $field_name,
+      'name' => $field_name,
+      'entity_type' => 'node',
       'type' => 'text',
       'cardinality' => FIELD_CARDINALITY_UNLIMITED,
     );
diff --git a/core/modules/system/lib/Drupal/system/Tests/Menu/TreeOutputTest.php b/core/modules/system/lib/Drupal/system/Tests/Menu/TreeOutputTest.php
index 01794f0..982a70d 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Menu/TreeOutputTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Menu/TreeOutputTest.php
@@ -14,7 +14,7 @@
  */
 class TreeOutputTest extends DrupalUnitTestBase {
 
-  public static $modules = array('system', 'menu_link');
+  public static $modules = array('system', 'menu_link', 'field');
 
   /**
    * Dummy link structure acceptable for menu_tree_output().
diff --git a/core/modules/system/lib/Drupal/system/Tests/Plugin/ContextPluginTest.php b/core/modules/system/lib/Drupal/system/Tests/Plugin/ContextPluginTest.php
index b04e2d8..262537b 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Plugin/ContextPluginTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Plugin/ContextPluginTest.php
@@ -17,7 +17,7 @@
  */
 class ContextPluginTest extends DrupalUnitTestBase {
 
-  public static $modules = array('system', 'user', 'node');
+  public static $modules = array('system', 'user', 'node', 'field');
 
   public static function getInfo() {
     return array(
diff --git a/core/modules/system/lib/Drupal/system/Tests/Upgrade/FieldUpgradePathTest.php b/core/modules/system/lib/Drupal/system/Tests/Upgrade/FieldUpgradePathTest.php
index dd13cf9..c00599b 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Upgrade/FieldUpgradePathTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Upgrade/FieldUpgradePathTest.php
@@ -6,7 +6,9 @@
  */
 
 namespace Drupal\system\Tests\Upgrade;
+use Drupal\Core\Entity\DatabaseStorageController;
 use Drupal\Core\Language\Language;
+use Drupal\field\Plugin\Core\Entity\Field;
 
 /**
  * Tests upgrade of system variables.
@@ -128,20 +130,14 @@ function testFieldUpgradeToConfig() {
     unset($config['uuid']);
     $this->assertEqual($config, array(
       'id' => 'body',
+      'entity_type' => 'node',
       'type' => 'text_with_summary',
       'module' => 'text',
       'active' => '1',
       'settings' => array(),
-      'storage' => array(
-        'type' => 'field_sql_storage',
-        'module' => 'field_sql_storage',
-        'active' => '1',
-        'settings' => array(),
-      ),
       'locked' => 0,
       'cardinality' => 1,
       'translatable' => 0,
-      'entity_types' => array('node'),
       'indexes' => array(
         'format' => array('format')
       ),
@@ -160,7 +156,6 @@ function testFieldUpgradeToConfig() {
         'id' => "node.$node_type.body",
         'field_uuid' => $field_uuid,
         'field_type' => 'text_with_summary',
-        'entity_type' => 'node',
         'bundle' => $node_type,
         'label' => 'Body',
         'description' => '',
@@ -209,16 +204,10 @@ function testFieldUpgradeToConfig() {
     // The deleted field uuid and deleted instance field_uuid must match.
     $this->assertEqual($deleted_field['uuid'], $deleted_instance['field_uuid']);
 
-    // Check that pre-existing deleted field values are read correctly.
-    $entity = _field_create_entity_from_ids((object) array(
-      'entity_type' => 'node',
-      'bundle' => 'article',
-      'entity_id' => 2,
-      'revision_id' => 2,
-    ));
-    field_attach_load('node', array(2 => $entity), FIELD_LOAD_CURRENT, array('instance' => entity_create('field_instance', $deleted_instance)));
-    $deleted_value = $entity->get('test_deleted_field');
-    $this->assertEqual($deleted_value[Language::LANGCODE_NOT_SPECIFIED][0]['value'], 'Some deleted value');
+    // Check that pre-existing deleted field table is renamed correctly.
+    $field_entity = new Field($deleted_field);
+    $table_name = DatabaseStorageController::_fieldTableName($field_entity);
+    $this->assertEqual("field_deleted_data_" . substr(hash('sha256', $deleted_field['uuid']), 0, 10), $table_name);
 
     // Check that creation of a new node works as expected.
     $value = $this->randomName();
diff --git a/core/modules/system/lib/Drupal/system/Tests/Upgrade/UserPictureUpgradePathTest.php b/core/modules/system/lib/Drupal/system/Tests/Upgrade/UserPictureUpgradePathTest.php
index dd9bcf9..9b513b8 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Upgrade/UserPictureUpgradePathTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Upgrade/UserPictureUpgradePathTest.php
@@ -52,7 +52,7 @@ public function testUserPictureUpgrade() {
 
     // Check file usage for the default image.
     $usage = file_usage()->listUsage($file);
-    $field = field_info_field('user_picture');
+    $field = field_info_field('user', 'user_picture');
     $this->assertTrue(isset($usage['image']['default_image'][$field['uuid']]));
 
     $this->assertEqual($instance['settings']['max_resolution'], '800x800', 'User picture maximum resolution has been migrated.');
diff --git a/core/modules/system/tests/modules/entity_test/entity_test.install b/core/modules/system/tests/modules/entity_test/entity_test.install
index d6f1b34..346eccb 100644
--- a/core/modules/system/tests/modules/entity_test/entity_test.install
+++ b/core/modules/system/tests/modules/entity_test/entity_test.install
@@ -9,14 +9,6 @@
  * Implements hook_install().
  */
 function entity_test_install() {
-  // Auto-create a field for testing.
-  entity_create('field_entity', array(
-    'field_name' => 'field_test_text',
-    'type' => 'text',
-    'cardinality' => 1,
-    'translatable' => FALSE,
-  ))->save();
-
   $entity_types = array(
     'entity_test',
     'entity_test_rev',
@@ -24,6 +16,14 @@ function entity_test_install() {
     'entity_test_mulrev',
   );
   foreach ($entity_types as $entity_type) {
+    // Auto-create fields for testing.
+    entity_create('field_entity', array(
+      'name' => 'field_test_text',
+      'entity_type' => $entity_type,
+      'type' => 'text',
+      'cardinality' => 1,
+      'translatable' => FALSE,
+    ))->save();
     entity_create('field_instance', array(
       'entity_type' => $entity_type,
       'field_name' => 'field_test_text',
diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/views/argument_default/Tid.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/views/argument_default/Tid.php
index 4771782..6d01e65 100644
--- a/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/views/argument_default/Tid.php
+++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/views/argument_default/Tid.php
@@ -135,12 +135,12 @@ public function getArgument() {
       // Just check, if a node could be detected.
       if ($node) {
         $taxonomy = array();
-        $fields = field_info_instances('node', $node->type);
-        foreach ($fields as $name => $info) {
-          $field_info = field_info_field($name);
-          if ($field_info['type'] == 'taxonomy_term_reference') {
-            foreach (field_get_items($node, $name) as $item) {
-              $taxonomy[$item['tid']] = $field_info['settings']['allowed_values'][0]['vocabulary'];
+        $instances = field_info_instances('node', $node->type);
+        foreach ($instances as $instance) {
+          $field = $instance->getField();
+          if ($field['type'] == 'taxonomy_term_reference') {
+            foreach (field_get_items($node, $field['name']) as $item) {
+              $taxonomy[$item['tid']] = $field['settings']['allowed_values'][0]['vocabulary'];
             }
           }
         }
diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/RssTest.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/RssTest.php
index c9b8078..905cc14 100644
--- a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/RssTest.php
+++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/RssTest.php
@@ -38,7 +38,8 @@ function setUp() {
     $this->field_name = 'taxonomy_' . $this->vocabulary->id();
 
     $this->field = entity_create('field_entity', array(
-      'field_name' => $this->field_name,
+      'name' => $this->field_name,
+      'entity_type' => 'node',
       'type' => 'taxonomy_term_reference',
       'cardinality' => FIELD_CARDINALITY_UNLIMITED,
       'settings' => array(
diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TaxonomyTermReferenceItemTest.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TaxonomyTermReferenceItemTest.php
index 2308f63..c5e96f7 100644
--- a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TaxonomyTermReferenceItemTest.php
+++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TaxonomyTermReferenceItemTest.php
@@ -45,7 +45,8 @@ public function setUp() {
     $vocabulary->save();
 
     entity_create('field_entity', array(
-      'field_name' => 'field_test_taxonomy',
+      'name' => 'field_test_taxonomy',
+      'entity_type' => 'entity_test',
       'type' => 'taxonomy_term_reference',
       'cardinality' => FIELD_CARDINALITY_UNLIMITED,
       'settings' => array(
diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermFieldMultipleVocabularyTest.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermFieldMultipleVocabularyTest.php
index c19ce9d..4cfb173 100644
--- a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermFieldMultipleVocabularyTest.php
+++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermFieldMultipleVocabularyTest.php
@@ -43,7 +43,8 @@ function setUp() {
     // Set up a field and instance.
     $this->field_name = drupal_strtolower($this->randomName());
     entity_create('field_entity', array(
-      'field_name' => $this->field_name,
+      'name' => $this->field_name,
+      'entity_type' => 'entity_test',
       'type' => 'taxonomy_term_reference',
       'cardinality' => FIELD_CARDINALITY_UNLIMITED,
       'settings' => array(
@@ -125,7 +126,7 @@ function testTaxonomyTermFieldMultipleVocabularies() {
     $this->assertNoText($term2->label(), 'Term 2 name is not displayed.');
 
     // Verify that field and instance settings are correct.
-    $field_info = field_info_field($this->field_name);
+    $field_info = field_info_field('entity_test', $this->field_name);
     $this->assertEqual(count($field_info['settings']['allowed_values']), 1, 'Only one vocabulary is allowed for the field.');
 
     // The widget should still be displayed.
diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermFieldTest.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermFieldTest.php
index e893001..7903eb5 100644
--- a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermFieldTest.php
+++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermFieldTest.php
@@ -46,8 +46,9 @@ function setUp() {
     // Setup a field and instance.
     $this->field_name = drupal_strtolower($this->randomName());
     $this->field = entity_create('field_entity', array(
-      'field_name' => $this->field_name,
+      'name' => $this->field_name,
       'type' => 'taxonomy_term_reference',
+      'entity_type' => 'entity_test',
       'settings' => array(
         'allowed_values' => array(
           array(
@@ -159,7 +160,7 @@ function testTaxonomyTermFieldChangeMachineName() {
     $this->vocabulary->save();
 
     // Check that the field instance is still attached to the vocabulary.
-    $field = field_info_field($this->field_name);
+    $field = field_info_field('entity_test', $this->field_name);
     $allowed_values = $field['settings']['allowed_values'];
     $this->assertEqual($allowed_values[0]['vocabulary'], $new_name, 'Index 0: Machine name was updated correctly.');
     $this->assertEqual($allowed_values[1]['vocabulary'], $new_name, 'Index 1: Machine name was updated correctly.');
diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermIndexTest.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermIndexTest.php
index 8fa30c3..cc36b9e 100644
--- a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermIndexTest.php
+++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermIndexTest.php
@@ -34,7 +34,8 @@ function setUp() {
 
     $this->field_name_1 = drupal_strtolower($this->randomName());
     entity_create('field_entity', array(
-      'field_name' => $this->field_name_1,
+      'name' => $this->field_name_1,
+      'entity_type' => 'node',
       'type' => 'taxonomy_term_reference',
       'cardinality' => FIELD_CARDINALITY_UNLIMITED,
       'settings' => array(
@@ -64,7 +65,8 @@ function setUp() {
 
     $this->field_name_2 = drupal_strtolower($this->randomName());
     entity_create('field_entity', array(
-      'field_name' => $this->field_name_2,
+      'name' => $this->field_name_2,
+      'entity_type' => 'node',
       'type' => 'taxonomy_term_reference',
       'cardinality' => FIELD_CARDINALITY_UNLIMITED,
       'settings' => array(
diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermTest.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermTest.php
index 9dbf118..00ac268 100644
--- a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermTest.php
+++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermTest.php
@@ -29,7 +29,8 @@ function setUp() {
     $this->vocabulary = $this->createVocabulary();
 
     $field = array(
-      'field_name' => 'taxonomy_' . $this->vocabulary->id(),
+      'name' => 'taxonomy_' . $this->vocabulary->id(),
+      'entity_type' => 'node',
       'type' => 'taxonomy_term_reference',
       'cardinality' => FIELD_CARDINALITY_UNLIMITED,
       'settings' => array(
diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TokenReplaceTest.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TokenReplaceTest.php
index 622eae7..4b2fe19 100644
--- a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TokenReplaceTest.php
+++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TokenReplaceTest.php
@@ -30,7 +30,8 @@ function setUp() {
     $this->langcode = Language::LANGCODE_NOT_SPECIFIED;
     $this->field_name = 'taxonomy_' . $this->vocabulary->id();
     entity_create('field_entity', array(
-      'field_name' => $this->field_name,
+      'name' => $this->field_name,
+      'entity_type' => 'node',
       'type' => 'taxonomy_term_reference',
       'cardinality' => FIELD_CARDINALITY_UNLIMITED,
       'settings' => array(
diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/Views/TaxonomyTestBase.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/Views/TaxonomyTestBase.php
index e7c7031..6e5e7ff 100644
--- a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/Views/TaxonomyTestBase.php
+++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/Views/TaxonomyTestBase.php
@@ -78,7 +78,8 @@ protected function mockStandardInstall() {
     $this->vocabulary->save();
     $this->field_name = 'field_' . $this->vocabulary->id();
     entity_create('field_entity', array(
-      'field_name' => $this->field_name,
+      'name' => $this->field_name,
+      'entity_type' => 'node',
       'type' => 'taxonomy_term_reference',
       // Set cardinality to unlimited for tagging.
       'cardinality' => FIELD_CARDINALITY_UNLIMITED,
diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/VocabularyUnitTest.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/VocabularyUnitTest.php
index fec21c3..e70966c 100644
--- a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/VocabularyUnitTest.php
+++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/VocabularyUnitTest.php
@@ -155,7 +155,8 @@ function testTaxonomyVocabularyLoadMultiple() {
   function testTaxonomyVocabularyChangeMachineName() {
     // Add a field instance to the vocabulary.
     entity_create('field_entity', array(
-      'field_name' => 'field_test',
+      'name' => 'field_test',
+      'entity_type' => 'taxonomy_term',
       'type' => 'test_field',
     ))->save();
     entity_create('field_instance', array(
@@ -187,7 +188,8 @@ function testUninstallReinstall() {
     // removed when the module is uninstalled.
     $this->field_name = drupal_strtolower($this->randomName() . '_field_name');
     $this->field_definition = array(
-      'field_name' => $this->field_name,
+      'name' => $this->field_name,
+      'entity_type' => 'taxonomy_term',
       'type' => 'text',
       'cardinality' => 4
     );
diff --git a/core/modules/taxonomy/taxonomy.install b/core/modules/taxonomy/taxonomy.install
index 860cde3..30dfd4c 100644
--- a/core/modules/taxonomy/taxonomy.install
+++ b/core/modules/taxonomy/taxonomy.install
@@ -6,12 +6,17 @@
  */
 
 use Drupal\Component\Uuid\Uuid;
+use Drupal\Core\Entity\DatabaseStorageController;
 use Drupal\field\Plugin\Core\Entity\Field;
 
 /**
  * Implements hook_uninstall().
  */
 function taxonomy_uninstall() {
+  Drupal::entityManager()->addNamespaces(new ArrayIterator(array(
+    'Drupal\taxonomy' => DRUPAL_ROOT . '/core/modules/taxonomy/lib',
+  )));
+  drupal_classloader_register('taxonomy', 'core/modules/taxonomy');
   // Remove taxonomy_term bundles.
   $config_names = config_get_storage_names_with_prefix('taxonomy.vocabulary.');
   foreach ($config_names as $config_name) {
@@ -356,12 +361,12 @@ function taxonomy_update_8007() {
   foreach (config_get_storage_names_with_prefix('field.field.') as $config_name) {
     $field_config = config($config_name);
     // Only update taxonomy reference fields that use the default SQL storage.
-    if ($field_config->get('type') == 'taxonomy_term_reference' && $field_config->get('storage.type') == 'field_sql_storage') {
+    if ($field_config->get('type') == 'taxonomy_term_reference') {
       $field = new Field($field_config->get());
 
       $tables = array(
-        _field_sql_storage_tablename($field),
-        _field_sql_storage_revision_tablename($field),
+        DatabaseStorageController::_fieldTableName($field),
+        DatabaseStorageController::_fieldRevisionTableName($field),
       );
 
       foreach ($tables as $table_name) {
diff --git a/core/modules/taxonomy/taxonomy.module b/core/modules/taxonomy/taxonomy.module
index 402a8e6..6dc62b9 100644
--- a/core/modules/taxonomy/taxonomy.module
+++ b/core/modules/taxonomy/taxonomy.module
@@ -5,6 +5,7 @@
  * Enables the organization of content into categories.
  */
 
+use Drupal\Core\Entity\DatabaseStorageController;
 use Drupal\node\Plugin\Core\Entity\Node;
 use Drupal\taxonomy\Plugin\Core\Entity\Term;
 use Drupal\taxonomy\Plugin\Core\Entity\Vocabulary;
@@ -1116,18 +1117,18 @@ function taxonomy_node_insert(EntityInterface $node) {
 function taxonomy_build_node_index($node) {
   // We maintain a denormalized table of term/node relationships, containing
   // only data for current, published nodes.
-  $status = NULL;
-  if (config('taxonomy.settings')->get('maintain_index_table')) {
-    // If a node property is not set in the node object when $node->save() is
-    // called, the old value from $node->original is used.
-    if (!empty($node->original)) {
-      $status = (int)(!empty($node->status) || (!isset($node->status) && !empty($node->original->status)));
-      $sticky = (int)(!empty($node->sticky) || (!isset($node->sticky) && !empty($node->original->sticky)));
-    }
-    else {
-      $status = (int)(!empty($node->status));
-      $sticky = (int)(!empty($node->sticky));
-    }
+  if (!config('taxonomy.settings')->get('maintain_index_table') || !Drupal::entityManager()->getStorageController('node') instanceof DatabaseStorageController) {
+    return;
+  }
+  // If a node property is not set in the node object when $node->save() is
+  // called, the old value from $node->original is used.
+  if (!empty($node->original)) {
+    $status = (int)(!empty($node->status) || (!isset($node->status) && !empty($node->original->status)));
+    $sticky = (int)(!empty($node->sticky) || (!isset($node->sticky) && !empty($node->original->sticky)));
+  }
+  else {
+    $status = (int)(!empty($node->status));
+    $sticky = (int)(!empty($node->sticky));
   }
   // We only maintain the taxonomy index for published nodes.
   if ($status && $node->isDefaultRevision()) {
@@ -1135,8 +1136,8 @@ function taxonomy_build_node_index($node) {
     $tid_all = array();
     foreach (field_info_instances('node', $node->type) as $instance) {
       $field_name = $instance['field_name'];
-      $field = field_info_field($field_name);
-      if ($field['module'] == 'taxonomy' && $field['storage']['type'] == 'field_sql_storage') {
+      $field = $instance->getField();
+      if ($field['module'] == 'taxonomy') {
         // If a field value is not set in the node object when $node->save() is
         // called, the old value from $node->original is used.
         if (isset($node->{$field_name})) {
diff --git a/core/modules/taxonomy/taxonomy.views.inc b/core/modules/taxonomy/taxonomy.views.inc
index 5646268..01fbba2 100644
--- a/core/modules/taxonomy/taxonomy.views.inc
+++ b/core/modules/taxonomy/taxonomy.views.inc
@@ -6,6 +6,7 @@
  *
  * @ingroup views_module_handlers
  */
+use Drupal\Core\Entity\DatabaseStorageController;
 
 /**
  * Implements hook_views_data().
@@ -335,8 +336,8 @@ function taxonomy_views_data_alter(&$data) {
  *
  * @see field_views_field_default_views_data()
  */
-function taxonomy_field_views_data($field) {
-  $data = field_views_field_default_views_data($field);
+function taxonomy_field_views_data($field, $sql_entity_types) {
+  $data = field_views_field_default_views_data($field, $sql_entity_types);
   foreach ($data as $table_name => $table_data) {
     foreach ($table_data as $field_name => $field_data) {
       if (isset($field_data['filter']) && $field_name != 'delta') {
@@ -363,8 +364,8 @@ function taxonomy_field_views_data($field) {
  *
  * Views integration to provide reverse relationships on term references.
  */
-function taxonomy_field_views_data_views_data_alter(&$data, $field) {
-  foreach ($field['bundles'] as $entity_type => $bundles) {
+function taxonomy_field_views_data_views_data_alter(&$data, $field, $sql_entity_types) {
+  foreach ($sql_entity_types as $entity_type) {
     $entity_info = entity_get_info($entity_type);
     $pseudo_field_name = 'reverse_' . $field['field_name'] . '_' . $entity_type;
 
@@ -379,7 +380,7 @@ function taxonomy_field_views_data_views_data_alter(&$data, $field) {
       'help' => t('Relate each @entity with a @field set to the term.', array('@entity' => $entity, '@field' => $label)),
       'id' => 'entity_reverse',
       'field_name' => $field['field_name'],
-      'field table' => _field_sql_storage_tablename($field),
+      'field table' => DatabaseStorageController::_fieldTableName($field),
       'field field' => $field['field_name'] . '_target_id',
       'base' => $entity_info['base_table'],
       'base field' => $entity_info['entity_keys']['id'],
diff --git a/core/modules/telephone/lib/Drupal/telephone/Tests/TelephoneFieldTest.php b/core/modules/telephone/lib/Drupal/telephone/Tests/TelephoneFieldTest.php
index 6158f07..8e290ba 100644
--- a/core/modules/telephone/lib/Drupal/telephone/Tests/TelephoneFieldTest.php
+++ b/core/modules/telephone/lib/Drupal/telephone/Tests/TelephoneFieldTest.php
@@ -21,7 +21,6 @@ class TelephoneFieldTest extends WebTestBase {
    */
   public static $modules = array(
     'field',
-    'field_sql_storage',
     'node',
     'telephone'
   );
@@ -54,7 +53,8 @@ function testTelephoneField() {
 
     // Add the telepone field to the article content type.
     entity_create('field_entity', array(
-      'field_name' => 'field_telephone',
+      'name' => 'field_telephone',
+      'entity_type' => 'node',
       'type' => 'telephone',
     ))->save();
     entity_create('field_instance', array(
diff --git a/core/modules/telephone/lib/Drupal/telephone/Tests/TelephoneItemTest.php b/core/modules/telephone/lib/Drupal/telephone/Tests/TelephoneItemTest.php
index bd3633b..6049260 100644
--- a/core/modules/telephone/lib/Drupal/telephone/Tests/TelephoneItemTest.php
+++ b/core/modules/telephone/lib/Drupal/telephone/Tests/TelephoneItemTest.php
@@ -36,7 +36,8 @@ public function setUp() {
 
     // Create a telephone field and instance for validation.
     entity_create('field_entity', array(
-      'field_name' => 'field_test',
+      'name' => 'field_test',
+      'entity_type' => 'entity_test',
       'type' => 'telephone',
     ))->save();
     entity_create('field_instance', array(
diff --git a/core/modules/text/lib/Drupal/text/Tests/Formatter/TextPlainUnitTest.php b/core/modules/text/lib/Drupal/text/Tests/Formatter/TextPlainUnitTest.php
index 0a2b900..f568103 100644
--- a/core/modules/text/lib/Drupal/text/Tests/Formatter/TextPlainUnitTest.php
+++ b/core/modules/text/lib/Drupal/text/Tests/Formatter/TextPlainUnitTest.php
@@ -26,7 +26,7 @@ class TextPlainUnitTest extends DrupalUnitTestBase {
    *
    * @var array
    */
-  public static $modules = array('entity', 'field', 'field_sql_storage', 'text', 'entity_test', 'system');
+  public static $modules = array('entity', 'field', 'text', 'entity_test', 'system');
 
   /**
    * Contains rendered content.
@@ -68,7 +68,8 @@ function setUp() {
     $this->formatter_settings = array();
 
     $this->field = entity_create('field_entity', array(
-      'field_name' => $this->field_name,
+      'name' => $this->field_name,
+      'entity_type' => $this->entity_type,
       'type' => $this->field_type,
       'settings' => $this->field_settings,
     ));
diff --git a/core/modules/text/lib/Drupal/text/Tests/TextFieldTest.php b/core/modules/text/lib/Drupal/text/Tests/TextFieldTest.php
index c349d6d..d42a65d 100644
--- a/core/modules/text/lib/Drupal/text/Tests/TextFieldTest.php
+++ b/core/modules/text/lib/Drupal/text/Tests/TextFieldTest.php
@@ -50,7 +50,8 @@ function testTextFieldValidation() {
     // Create a field with settings to validate.
     $max_length = 3;
     $this->field = entity_create('field_entity', array(
-      'field_name' => drupal_strtolower($this->randomName()),
+      'name' => drupal_strtolower($this->randomName()),
+      'entity_type' => 'entity_test',
       'type' => 'text',
       'settings' => array(
         'max_length' => $max_length,
@@ -93,7 +94,8 @@ function _testTextfieldWidgets($field_type, $widget_type) {
     $entity_type = 'entity_test';
     $this->field_name = drupal_strtolower($this->randomName());
     $this->field = entity_create('field_entity', array(
-      'field_name' => $this->field_name,
+      'name' => $this->field_name,
+      'entity_type' => 'entity_test',
       'type' => $field_type
     ));
     $this->field->save();
@@ -161,7 +163,8 @@ function _testTextfieldWidgetsFormatted($field_type, $widget_type) {
     // Setup a field and instance
     $this->field_name = drupal_strtolower($this->randomName());
     $this->field = entity_create('field_entity', array(
-      'field_name' => $this->field_name,
+      'name' => $this->field_name,
+      'entity_type' => 'entity_test',
       'type' => $field_type
     ));
     $this->field->save();
diff --git a/core/modules/user/lib/Drupal/user/Tests/UserEntityTest.php b/core/modules/user/lib/Drupal/user/Tests/UserEntityTest.php
index 14d885c..c073b95 100644
--- a/core/modules/user/lib/Drupal/user/Tests/UserEntityTest.php
+++ b/core/modules/user/lib/Drupal/user/Tests/UserEntityTest.php
@@ -23,7 +23,7 @@ class UserEntityTest extends DrupalUnitTestBase {
    *
    * @var array
    */
-  public static $modules = array('system', 'user');
+  public static $modules = array('system', 'user', 'field');
 
   public static function getInfo() {
     return array(
diff --git a/core/modules/user/lib/Drupal/user/Tests/UserRegistrationTest.php b/core/modules/user/lib/Drupal/user/Tests/UserRegistrationTest.php
index 32dc5cc..fd77d77 100644
--- a/core/modules/user/lib/Drupal/user/Tests/UserRegistrationTest.php
+++ b/core/modules/user/lib/Drupal/user/Tests/UserRegistrationTest.php
@@ -196,8 +196,9 @@ function testRegistrationDefaultValues() {
   function testRegistrationWithUserFields() {
     // Create a field, and an instance on 'user' entity type.
     $field = entity_create('field_entity', array(
+      'name' => 'test_user_field',
+      'entity_type' => 'user',
       'type' => 'test_field',
-      'field_name' => 'test_user_field',
       'cardinality' => 1,
     ));
     $field->save();
diff --git a/core/modules/user/lib/Drupal/user/UserStorageController.php b/core/modules/user/lib/Drupal/user/UserStorageController.php
index 8b4653c..930a985 100644
--- a/core/modules/user/lib/Drupal/user/UserStorageController.php
+++ b/core/modules/user/lib/Drupal/user/UserStorageController.php
@@ -11,7 +11,9 @@
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Password\PasswordInterface;
 use Drupal\Core\Database\Connection;
+use Drupal\field\FieldInfo;
 use Drupal\user\UserDataInterface;
+use Symfony\Component\DependencyInjection\Container;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Drupal\Core\Entity\DatabaseStorageControllerNG;
 
@@ -46,13 +48,15 @@ class UserStorageController extends DatabaseStorageControllerNG implements UserS
    *   An array of entity info for the entity type.
    * @param \Drupal\Core\Database\Connection $database
    *   The database connection to be used.
+   * @param \Drupal\field\FieldInfo $field_info
+   *   The field info service.
    * @param \Drupal\Core\Password\PasswordInterface $password
    *   The password hashing service.
    * @param \Drupal\user\UserDataInterface $user_data
    *   The user data service.
    */
-  public function __construct($entity_type, $entity_info, Connection $database, PasswordInterface $password, UserDataInterface $user_data) {
-    parent::__construct($entity_type, $entity_info, $database);
+  public function __construct($entity_type, $entity_info, Connection $database, FieldInfo $field_info, PasswordInterface $password, UserDataInterface $user_data) {
+    parent::__construct($entity_type, $entity_info, $database, $field_info);
 
     $this->password = $password;
     $this->userData = $user_data;
@@ -66,6 +70,7 @@ public static function createInstance(ContainerInterface $container, $entity_typ
       $entity_type,
       $entity_info,
       $container->get('database'),
+      $container->get('field.info'),
       $container->get('password'),
       $container->get('user.data')
     );
@@ -155,14 +160,9 @@ public function deleteUserRoles(array $uids) {
    * {@inheritdoc}
    */
   protected function invokeHook($hook, EntityInterface $entity) {
-    $function = 'field_attach_' . $hook;
-    // @todo: field_attach_delete_revision() is named the wrong way round,
-    // consider renaming it.
-    if ($function == 'field_attach_revision_delete') {
-      $function = 'field_attach_delete_revision';
-    }
-    if (!empty($this->entityInfo['fieldable']) && function_exists($function)) {
-      $function($entity->getBCEntity());
+    $method = Container::camelize('field_' . $hook);
+    if (!empty($this->entityInfo['fieldable']) && method_exists($this, $method)) {
+      $this->$method($entity->getBCEntity());
     }
 
     // Invoke the hook.
diff --git a/core/modules/user/user.install b/core/modules/user/user.install
index 871c18d..ae76017 100644
--- a/core/modules/user/user.install
+++ b/core/modules/user/user.install
@@ -268,7 +268,8 @@ function user_install() {
  */
 function user_install_picture_field() {
   $field = array(
-    'field_name' => 'user_picture',
+    'name' => 'user_picture',
+    'entity_type' => 'user',
     'module' => 'image',
     'type' => 'image',
     'cardinality' => 1,
diff --git a/core/modules/views/lib/Drupal/views/Tests/DefaultViewsTest.php b/core/modules/views/lib/Drupal/views/Tests/DefaultViewsTest.php
index 730b123..55ccdf7 100644
--- a/core/modules/views/lib/Drupal/views/Tests/DefaultViewsTest.php
+++ b/core/modules/views/lib/Drupal/views/Tests/DefaultViewsTest.php
@@ -62,7 +62,8 @@ protected function setUp() {
     // Setup a field and instance.
     $this->field_name = drupal_strtolower($this->randomName());
     entity_create('field_entity', array(
-      'field_name' => $this->field_name,
+      'name' => $this->field_name,
+      'entity_type' => 'node',
       'type' => 'taxonomy_term_reference',
       'settings' => array(
         'allowed_values' => array(
diff --git a/core/modules/views/lib/Drupal/views/Tests/Wizard/TaggedWithTest.php b/core/modules/views/lib/Drupal/views/Tests/Wizard/TaggedWithTest.php
index 2f870d8..0d4168c 100644
--- a/core/modules/views/lib/Drupal/views/Tests/Wizard/TaggedWithTest.php
+++ b/core/modules/views/lib/Drupal/views/Tests/Wizard/TaggedWithTest.php
@@ -56,7 +56,8 @@ function setUp() {
 
     // Create the tag field itself.
     $this->tag_field = entity_create('field_entity', array(
-      'field_name' => 'field_views_testing_tags',
+      'name' => 'field_views_testing_tags',
+      'entity_type' => 'node',
       'type' => 'taxonomy_term_reference',
       'cardinality' => FIELD_CARDINALITY_UNLIMITED,
       'settings' => array(
diff --git a/core/profiles/standard/config/field.field.field_image.yml b/core/profiles/standard/config/field.field.field_image.yml
deleted file mode 100644
index 0fc032a..0000000
--- a/core/profiles/standard/config/field.field.field_image.yml
+++ /dev/null
@@ -1,34 +0,0 @@
-id: field_image
-type: image
-module: image
-active: '1'
-settings:
-  uri_scheme: public
-  default_image: false
-  column_groups:
-    file:
-      label: File
-      columns:
-        - target_id
-        - width
-        - height
-    alt:
-      label: Alt
-      translatable: true
-    title:
-      label: Title
-      translatable: true
-storage:
-  type: field_sql_storage
-  module: field_sql_storage
-  active: '1'
-  settings: {  }
-locked: '0'
-cardinality: '1'
-translatable: '0'
-entity_types: {  }
-indexes:
-  target_id:
-    - target_id
-status: 1
-langcode: und
diff --git a/core/profiles/standard/config/field.field.field_tags.yml b/core/profiles/standard/config/field.field.field_tags.yml
deleted file mode 100644
index e0f6952..0000000
--- a/core/profiles/standard/config/field.field.field_tags.yml
+++ /dev/null
@@ -1,23 +0,0 @@
-id: field_tags
-type: taxonomy_term_reference
-module: taxonomy
-active: '1'
-settings:
-  allowed_values:
-    -
-      vocabulary: tags
-      parent: 0
-storage:
-  type: field_sql_storage
-  module: field_sql_storage
-  active: '1'
-  settings: {  }
-locked: '0'
-cardinality: '-1'
-translatable: '0'
-entity_types: {  }
-indexes:
-  target_id:
-    - target_id
-status: 1
-langcode: und
diff --git a/core/profiles/standard/config/field.field.node.field_image.yml b/core/profiles/standard/config/field.field.node.field_image.yml
new file mode 100644
index 0000000..f696897
--- /dev/null
+++ b/core/profiles/standard/config/field.field.node.field_image.yml
@@ -0,0 +1,35 @@
+id: node.field_image
+name: field_image
+entity_type: node
+type: image
+module: image
+active: '1'
+settings:
+  uri_scheme: public
+  default_image: false
+  column_groups:
+    file:
+      label: File
+      columns:
+        - target_id
+        - width
+        - height
+    alt:
+      label: Alt
+      translatable: true
+    title:
+      label: Title
+      translatable: true
+storage:
+  type: field_sql_storage
+  module: field_sql_storage
+  active: '1'
+  settings: {  }
+locked: '0'
+cardinality: '1'
+translatable: '0'
+indexes:
+  target_id:
+    - target_id
+status: 1
+langcode: und
diff --git a/core/profiles/standard/config/field.field.node.field_tags.yml b/core/profiles/standard/config/field.field.node.field_tags.yml
new file mode 100644
index 0000000..b31480e
--- /dev/null
+++ b/core/profiles/standard/config/field.field.node.field_tags.yml
@@ -0,0 +1,24 @@
+id: node.field_tags
+name: field_tags
+entity_type: node
+type: taxonomy_term_reference
+module: taxonomy
+active: '1'
+settings:
+  allowed_values:
+    -
+      vocabulary: tags
+      parent: 0
+storage:
+  type: field_sql_storage
+  module: field_sql_storage
+  active: '1'
+  settings: {  }
+locked: '0'
+cardinality: '-1'
+translatable: '0'
+indexes:
+  target_id:
+    - target_id
+status: 1
+langcode: und
