diff --git a/core/lib/Drupal/Core/Entity/DatabaseStorageController.php b/core/lib/Drupal/Core/Entity/DatabaseStorageController.php
index 2bed3f6..b7ae0b5 100644
--- a/core/lib/Drupal/Core/Entity/DatabaseStorageController.php
+++ b/core/lib/Drupal/Core/Entity/DatabaseStorageController.php
@@ -22,28 +22,9 @@
 /**
  * Defines a base entity controller class.
  *
- * Default implementation of Drupal\Core\Entity\EntityStorageControllerInterface.
- *
- * This class can be used as-is by most simple entity types. Entity types
- * requiring special handling can extend the class.
+ * This class only supports bare, non-content entities.
  */
-class DatabaseStorageController extends FieldableEntityStorageControllerBase {
-
-  /**
-   * Name of entity's revision database table field, if it supports revisions.
-   *
-   * Has the value FALSE if this entity does not use revisions.
-   *
-   * @var string
-   */
-  protected $revisionKey;
-
-  /**
-   * The table that stores revisions, if the entity supports revisions.
-   *
-   * @var string
-   */
-  protected $revisionTable;
+class DatabaseStorageController extends EntityStorageControllerBase {
 
   /**
    * Whether this entity type should use the static cache.
@@ -75,8 +56,7 @@ public static function createInstance(ContainerInterface $container, $entity_typ
     return new static(
       $entity_type,
       $entity_info,
-      $container->get('database'),
-      $container->get('field.info')
+      $container->get('database')
     );
   }
 
@@ -89,14 +69,11 @@ 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, FieldInfo $field_info) {
+  public function __construct($entity_type, array $entity_info, Connection $database) {
     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'])) {
@@ -113,15 +90,6 @@ public function __construct($entity_type, array $entity_info, Connection $databa
     else {
       $this->uuidKey = FALSE;
     }
-
-    // Check if the entity type supports revisions.
-    if (!empty($this->entityInfo['entity_keys']['revision'])) {
-      $this->revisionKey = $this->entityInfo['entity_keys']['revision'];
-      $this->revisionTable = $this->entityInfo['revision_table'];
-    }
-    else {
-      $this->revisionKey = FALSE;
-    }
   }
 
   /**
@@ -200,50 +168,21 @@ public function load($id) {
   }
 
   /**
-   * Implements \Drupal\Core\Entity\EntityStorageControllerInterface::loadRevision().
+   * {@inheritdoc}
    */
   public function loadRevision($revision_id) {
-    // Build and execute the query.
-    $query_result = $this->buildQuery(array(), $revision_id)->execute();
-
-    if (!empty($this->entityInfo['class'])) {
-      // 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));
-    }
-    $queried_entities = $query_result->fetchAllAssoc($this->idKey);
-
-    // Pass the loaded entities from the database through $this->attachLoad(),
-    // which attaches fields (if supported by the entity type) and calls the
-    // entity type specific load callback, for example hook_node_load().
-    if (!empty($queried_entities)) {
-      $this->attachLoad($queried_entities, $revision_id);
-    }
-    return reset($queried_entities);
+    throw new \Exception('Database storage controller does not support revisions.');
   }
 
   /**
-   * Implements \Drupal\Core\Entity\EntityStorageControllerInterface::deleteRevision().
+   * {@inheritdoc}
    */
   public function deleteRevision($revision_id) {
-    if ($revision = $this->loadRevision($revision_id)) {
-      // Prevent deletion if this is the default revision.
-      if ($revision->isDefaultRevision()) {
-        throw new EntityStorageException('Default revision can not be deleted');
-      }
-
-      $this->database->delete($this->revisionTable)
-        ->condition($this->revisionKey, $revision->getRevisionId())
-        ->execute();
-      $this->invokeFieldMethod('deleteRevision', $revision);
-      $this->deleteFieldItemsRevision($revision);
-      $this->invokeHook('revision_delete', $revision);
-    }
+    throw new \Exception('Database storage controller does not support revisions.');
   }
 
   /**
-   * Implements \Drupal\Core\Entity\EntityStorageControllerInterface::loadByProperties().
+   * {@inheritdoc}
    */
   public function loadByProperties(array $values = array()) {
     // Build a query to fetch the entity IDs.
@@ -271,19 +210,8 @@ protected function buildPropertyQuery(QueryInterface $entity_query, array $value
   /**
    * Builds the query to load the entity.
    *
-   * This has full revision support. For entities requiring special queries,
-   * the class can be extended, and the default query can be constructed by
-   * calling parent::buildQuery(). This is usually necessary when the object
-   * being loaded needs to be augmented with additional data from another
-   * table, such as loading node type into comments or vocabulary machine name
-   * into terms, however it can also support $conditions on different tables.
-   * See Drupal\comment\CommentStorageController::buildQuery() for an example.
-   *
    * @param array|null $ids
    *   An array of entity IDs, or NULL to load all entities.
-   * @param $revision_id
-   *   The ID of the revision to load, or FALSE if this query is asking for the
-   *   most current revision(s).
    *
    * @return SelectQuery
    *   A SelectQuery object for loading the entity.
@@ -293,37 +221,9 @@ protected function buildQuery($ids, $revision_id = FALSE) {
 
     $query->addTag($this->entityType . '_load_multiple');
 
-    if ($revision_id) {
-      $query->join($this->revisionTable, 'revision', "revision.{$this->idKey} = base.{$this->idKey} AND revision.{$this->revisionKey} = :revisionId", array(':revisionId' => $revision_id));
-    }
-    elseif ($this->revisionKey) {
-      $query->join($this->revisionTable, 'revision', "revision.{$this->revisionKey} = base.{$this->revisionKey}");
-    }
-
     // Add fields from the {entity} table.
     $entity_fields = drupal_schema_fields_sql($this->entityInfo['base_table']);
 
-    if ($this->revisionKey) {
-      // Add all fields from the {entity_revision} table.
-      $entity_revision_fields = drupal_map_assoc(drupal_schema_fields_sql($this->entityInfo['revision_table']));
-      // The id field is provided by entity, so remove it.
-      unset($entity_revision_fields[$this->idKey]);
-
-      // Remove all fields from the base table that are also fields by the same
-      // name in the revision table.
-      $entity_field_keys = array_flip($entity_fields);
-      foreach ($entity_revision_fields as $name) {
-        if (isset($entity_field_keys[$name])) {
-          unset($entity_fields[$entity_field_keys[$name]]);
-        }
-      }
-      $query->fields('revision', $entity_revision_fields);
-
-      // Compare revision id of the base and revision table, if equal then this
-      // is the default revision.
-      $query->addExpression('base.' . $this->revisionKey . ' = revision.' . $this->revisionKey, 'isDefaultRevision');
-    }
-
     $query->fields('base', $entity_fields);
 
     if ($ids) {
@@ -336,41 +236,21 @@ protected function buildQuery($ids, $revision_id = FALSE) {
   /**
    * Attaches data to entities upon loading.
    *
-   * This will attach fields, if the entity is fieldable. It calls
-   * hook_entity_load() for modules which need to add data to all entities.
-   * It also calls hook_TYPE_load() on the loaded entities. For example
-   * hook_node_load() or hook_user_load(). If your hook_TYPE_load()
-   * expects special parameters apart from the queried entities, you can set
-   * $this->hookLoadArguments prior to calling the method.
-   * See Drupal\node\NodeStorageController::attachLoad() for an example.
-   *
    * @param $queried_entities
    *   Associative array of query results, keyed on the entity ID.
    * @param $load_revision
    *   (optional) TRUE if the revision should be loaded, defaults to FALSE.
    */
   protected function attachLoad(&$queried_entities, $load_revision = FALSE) {
-    // Attach field values.
-    if ($this->entityInfo['fieldable']) {
-      $this->loadFieldItems($queried_entities, $load_revision ? static::FIELD_LOAD_REVISION : static::FIELD_LOAD_CURRENT);
-    }
-
     // Call hook_entity_load().
     foreach (\Drupal::moduleHandler()->getImplementations('entity_load') as $module) {
       $function = $module . '_entity_load';
       $function($queried_entities, $this->entityType);
     }
-    // Call hook_TYPE_load(). The first argument for hook_TYPE_load() are
-    // always the queried entities, followed by additional arguments set in
-    // $this->hookLoadArguments.
-    $args = array_merge(array($queried_entities), $this->hookLoadArguments);
-    foreach (\Drupal::moduleHandler()->getImplementations($this->entityType . '_load') as $module) {
-      call_user_func_array($module . '_' . $this->entityType . '_load', $args);
-    }
   }
 
   /**
-   * Implements \Drupal\Core\Entity\EntityStorageControllerInterface::create().
+   * {@inheritdoc}
    */
   public function create(array $values) {
     $entity_class = $this->entityInfo['class'];
@@ -393,7 +273,7 @@ public function create(array $values) {
   }
 
   /**
-   * Implements \Drupal\Core\Entity\EntityStorageControllerInterface::delete().
+   * {@inheritdoc}
    */
   public function delete(array $entities) {
     if (!$entities) {
@@ -414,19 +294,11 @@ public function delete(array $entities) {
         ->condition($this->idKey, $ids, 'IN')
         ->execute();
 
-      if ($this->revisionKey) {
-        $this->database->delete($this->revisionTable)
-          ->condition($this->idKey, $ids, 'IN')
-          ->execute();
-      }
-
       // Reset the cache as soon as the changes have been applied.
       $this->resetCache($ids);
 
       $entity_class::postDelete($this, $entities);
       foreach ($entities as $entity) {
-        $this->invokeFieldMethod('delete', $entity);
-        $this->deleteFieldItems($entity);
         $this->invokeHook('delete', $entity);
       }
       // Ignore slave server temporarily.
@@ -440,7 +312,7 @@ public function delete(array $entities) {
   }
 
   /**
-   * Implements \Drupal\Core\Entity\EntityStorageControllerInterface::save().
+   * {@inheritdoc}
    */
   public function save(EntityInterface $entity) {
     $transaction = $this->database->startTransaction();
@@ -451,39 +323,21 @@ public function save(EntityInterface $entity) {
       }
 
       $entity->preSave($this);
-      $this->invokeFieldMethod('preSave', $entity);
       $this->invokeHook('presave', $entity);
 
       if (!$entity->isNew()) {
-        if ($entity->isDefaultRevision()) {
-          $return = drupal_write_record($this->entityInfo['base_table'], $entity, $this->idKey);
-        }
-        else {
-          // @todo, should a different value be returned when saving an entity
-          // with $isDefaultRevision = FALSE?
-          $return = FALSE;
-        }
-        if ($this->revisionKey) {
-          $this->saveRevision($entity);
-        }
+        $return = drupal_write_record($this->entityInfo['base_table'], $entity, $this->idKey);
         $this->resetCache(array($entity->id()));
         $entity->postSave($this, TRUE);
-        $this->invokeFieldMethod('update', $entity);
-        $this->saveFieldItems($entity, TRUE);
         $this->invokeHook('update', $entity);
       }
       else {
         $return = drupal_write_record($this->entityInfo['base_table'], $entity);
-        if ($this->revisionKey) {
-          $this->saveRevision($entity);
-        }
         // Reset general caches, but keep caches specific to certain entities.
         $this->resetCache(array());
 
         $entity->enforceIsNew(FALSE);
         $entity->postSave($this, FALSE);
-        $this->invokeFieldMethod('insert', $entity);
-        $this->saveFieldItems($entity, FALSE);
         $this->invokeHook('insert', $entity);
       }
 
@@ -501,694 +355,10 @@ public function save(EntityInterface $entity) {
   }
 
   /**
-   * Saves an entity revision.
-   *
-   * @param \Drupal\Core\Entity\EntityInterface $entity
-   *   The entity object.
-   */
-  protected function saveRevision(EntityInterface $entity) {
-    // Convert the entity into an array as it might not have the same properties
-    // as the entity, it is just a raw structure.
-    $record = (array) $entity;
-
-    // When saving a new revision, set any existing revision ID to NULL so as to
-    // ensure that a new revision will actually be created.
-    if ($entity->isNewRevision() && $record[$this->revisionKey]) {
-      $record[$this->revisionKey] = NULL;
-    }
-
-    // Cast to object as preSaveRevision() expects one to be compatible with the
-    // upcoming NG storage controller.
-    $record = (object) $record;
-    $entity->preSaveRevision($this, $record);
-    $record = (array) $record;
-
-    if ($entity->isNewRevision()) {
-      drupal_write_record($this->revisionTable, $record);
-      if ($entity->isDefaultRevision()) {
-        $this->database->update($this->entityInfo['base_table'])
-          ->fields(array($this->revisionKey => $record[$this->revisionKey]))
-          ->condition($this->idKey, $entity->id())
-          ->execute();
-      }
-      $entity->setNewRevision(FALSE);
-    }
-    else {
-      drupal_write_record($this->revisionTable, $record, $this->revisionKey);
-    }
-    // Make sure to update the new revision key for the entity.
-    $entity->{$this->revisionKey} = $record[$this->revisionKey];
-  }
-
-  /**
    * {@inheritdoc}
    */
   public function getQueryServiceName() {
     return 'entity.query.sql';
   }
 
-  /**
-   * {@inheritdoc}
-   */
-  protected function doLoadFieldItems($entities, $age) {
-    $load_current = $age == static::FIELD_LOAD_CURRENT;
-
-    // Collect entities ids and bundles.
-    $bundles = array();
-    $ids = array();
-    foreach ($entities as $key => $entity) {
-      $bundles[$entity->bundle()] = TRUE;
-      $ids[] = $load_current ? $key : $entity->getRevisionId();
-    }
-
-    // Collect impacted fields.
-    $fields = array();
-    foreach ($bundles as $bundle => $v) {
-      foreach ($this->fieldInfo->getBundleInstances($this->entityType, $bundle) as $field_name => $instance) {
-        $fields[$field_name] = $instance->getField();
-      }
-    }
-
-    // Load field data.
-    $all_langcodes = array_keys(language_list());
-    foreach ($fields as $field_name => $field) {
-      $table = $load_current ? static::_fieldTableName($field) : static::_fieldRevisionTableName($field);
-
-      // If the field is translatable ensure that only values having valid
-      // languages are retrieved. Since we are loading values for multiple
-      // entities, we cannot limit the query to the available translations.
-      $langcodes = $field['translatable'] ? $all_langcodes : array(Language::LANGCODE_NOT_SPECIFIED);
-      $results = $this->database->select($table, 't')
-        ->fields('t')
-        ->condition($load_current ? 'entity_id' : 'revision_id', $ids, 'IN')
-        ->condition('deleted', 0)
-        ->condition('langcode', $langcodes, 'IN')
-        ->orderBy('delta')
-        ->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]->getTranslation($row->langcode)->{$field_name}[$delta_count[$row->entity_id][$row->langcode]] = $item;
-          $delta_count[$row->entity_id][$row->langcode]++;
-        }
-      }
-    }
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  protected function doSaveFieldItems(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);
-
-      // Delete and insert, rather than update, in case a value was added.
-      if ($update) {
-        // 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)
-            ->execute();
-        }
-        $this->database->delete($revision_name)
-          ->condition('entity_id', $id)
-          ->condition('revision_id', $vid)
-          ->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);
-
-      $langcodes = $field['translatable'] ? array_keys($entity->getTranslationLanguages()) : array(Language::LANGCODE_NOT_SPECIFIED);
-      foreach ($langcodes as $langcode) {
-        $items = $entity->getTranslation($langcode)->{$field_name}->getValue();
-        if (!isset($items)) {
-          continue;
-        }
-        $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);
-          $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 doDeleteFieldItems(EntityInterface $entity) {
-    foreach ($this->fieldInfo->getBundleInstances($entity->entityType(), $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 doDeleteFieldItemsRevision(EntityInterface $entity) {
-    $vid = $entity->getRevisionId();
-    if (isset($vid)) {
-      foreach ($this->fieldInfo->getBundleInstances($entity->entityType(), $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 onFieldCreate(FieldInterface $field) {
-    $schema = $this->_fieldSqlSchema($field);
-    foreach ($schema as $name => $table) {
-      $this->database->schema()->createTable($name, $table);
-    }
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function onFieldUpdate(FieldInterface $field) {
-    $original = $field->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 onFieldDelete(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 onInstanceDelete(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 onBundleRename($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}
-   */
-  protected function readFieldItemsToPurge(EntityInterface $entity, FieldInstanceInterface $instance) {
-    $field = $instance->getField();
-    $table_name = static::_fieldTableName($field);
-    $query = $this->database->select($table_name, 't', array('fetch' => \PDO::FETCH_ASSOC))
-      ->condition('entity_id', $entity->id())
-      ->orderBy('delta');
-    foreach ($field->getColumns() as $column_name => $data) {
-      $query->addField('t', static::_fieldColumnName($field, $column_name), $column_name);
-    }
-    return $query->execute()->fetchAll();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function purgeFieldItems(EntityInterface $entity, FieldInstanceInterface $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}
-   */
-  public function onFieldPurge(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\FieldInterface $field
-   *   The field object
-   * @param array $schema
-   *   The field schema array. Mandatory for upgrades, omit otherwise.
-   *
-   * @return array
-   *   The same as a hook_schema() implementation for the data and the
-   *   revision tables.
-   *
-   * @see hook_schema()
-   */
-  public static function _fieldSqlSchema(FieldInterface $field, array $schema = NULL) {
-    if ($field['deleted']) {
-      $description_current = "Data storage for deleted field {$field['id']} ({$field['entity_type']}, {$field['field_name']}).";
-      $description_revision = "Revision archive storage for deleted field {$field['id']} ({$field['entity_type']}, {$field['field_name']}).";
-    }
-    else {
-      $description_current = "Data storage for {$field['entity_type']} field {$field['field_name']}.";
-      $description_revision = "Revision archive storage for {$field['entity_type']} field {$field['field_name']}.";
-    }
-
-    $current = array(
-      'description' => $description_current,
-      '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'),
-      ),
-    );
-
-    if (!$schema) {
-      $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'] = $description_revision;
-    $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 \Drupal\field\FieldInterface $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 static::_generateFieldTableName($field, FALSE);
-    }
-  }
-
-  /**
-   * 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\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 static::_generateFieldTableName($field, TRUE);
-    }
-  }
-
-  /**
-   * Generates a safe and unanbiguous field table name.
-   *
-   * The method accounts for a maximum table name length of 64 characters, and
-   * takes care of disambiguation.
-   *
-   * @param \Drupal\field\FieldInterface $field
-   *   The field object.
-   * @param bool $revision
-   *   TRUE for revision table, FALSE otherwise.
-   *
-   * @return string
-   *   The final table name.
-   */
-  static protected function _generateFieldTableName($field, $revision) {
-    $separator = $revision ? '_revision__' : '__';
-    $table_name = $field->entity_type . $separator .  $field->name;
-    // Limit the string to 48 characters, keeping a 16 characters margin for db
-    // prefixes.
-    if (strlen($table_name) > 48) {
-      // Use a shorter separator, a truncated entity_type, and a hash of the
-      // field UUID.
-      $separator = $revision ? '_r__' : '__';
-      // Truncate to the same length for the current and revision tables.
-      $entity_type = substr($field->entity_type, 0, 34);
-      $field_hash = substr(hash('sha256', $field->uuid), 0, 10);
-      $table_name = $entity_type . $separator . $field_hash;
-    }
-    return $table_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\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\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
deleted file mode 100644
index 9fb88df..0000000
--- a/core/lib/Drupal/Core/Entity/DatabaseStorageControllerNG.php
+++ /dev/null
@@ -1,611 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\Core\Entity\DatabaseStorageControllerNG.
- */
-
-namespace Drupal\Core\Entity;
-
-use Drupal\Core\Language\Language;
-use Drupal\field\FieldInfo;
-use Drupal\Core\Entity\Query\QueryInterface;
-use Drupal\Core\Entity\EntityInterface;
-use Drupal\Core\Entity\DatabaseStorageController;
-use Drupal\Core\Entity\EntityStorageException;
-use Drupal\Component\Uuid\Uuid;
-use Drupal\Core\Database\Connection;
-
-/**
- * Implements Field API specific enhancements to the DatabaseStorageController class.
- *
- * @todo: Once all entity types have been converted, merge improvements into the
- * DatabaseStorageController class.
- *
- * See the EntityNG documentation for an explanation of "NG".
- *
- * @see \Drupal\Core\EntityNG
- */
-class DatabaseStorageControllerNG extends DatabaseStorageController {
-
-  /**
-   * The entity class to use.
-   *
-   * @var string
-   */
-  protected $entityClass;
-
-  /**
-   * The entity bundle key.
-   *
-   * @var string|bool
-   */
-  protected $bundleKey;
-
-  /**
-   * The table that stores properties, if the entity has multilingual support.
-   *
-   * @var string
-   */
-  protected $dataTable;
-
-  /**
-   * Overrides DatabaseStorageController::__construct().
-   */
-  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'];
-
-    // Check if the entity type has a dedicated table for properties.
-    if (!empty($this->entityInfo['data_table'])) {
-      $this->dataTable = $this->entityInfo['data_table'];
-    }
-
-    // Work-a-round to let load() get stdClass storage records without having to
-    // override it. We map storage records to entities in
-    // DatabaseStorageControllerNG:: mapFromStorageRecords().
-    // @todo: Remove this once this is moved in the main controller.
-    unset($this->entityInfo['class']);
-  }
-
-  /**
-   * Overrides DatabaseStorageController::create().
-   *
-   * @param array $values
-   *   An array of values to set, keyed by field name. The value has to be
-   *   the plain value of an entity field, i.e. an array of field items.
-   *   If no numerically indexed array is given, the value will be set for the
-   *   first field item. For example, to set the first item of a 'name'
-   *   field one can pass:
-   *   @code
-   *     $values = array('name' => array(0 => array('value' => 'the name')));
-   *   @endcode
-   *   or
-   *   @code
-   *     $values = array('name' => array('value' => 'the name'));
-   *   @endcode
-   *   If the 'name' field is a defined as 'string_item' which supports
-   *   setting its value by a string, it's also possible to just pass the name
-   *   string:
-   *   @code
-   *     $values = array('name' => 'the name');
-   *   @endcode
-   *
-   * @return \Drupal\Core\Entity\EntityInterface
-   *   A new entity object.
-   */
-  public function create(array $values) {
-    $entity_class = $this->entityClass;
-    $entity_class::preCreate($this, $values);
-
-    // We have to determine the bundle first.
-    $bundle = FALSE;
-    if ($this->bundleKey) {
-      if (!isset($values[$this->bundleKey])) {
-        throw new EntityStorageException(format_string('Missing bundle for entity type @type', array('@type' => $this->entityType)));
-      }
-      $bundle = $values[$this->bundleKey];
-    }
-    $entity = new $this->entityClass(array(), $this->entityType, $bundle);
-
-    foreach ($entity as $name => $field) {
-      if (isset($values[$name])) {
-        $entity->$name = $values[$name];
-      }
-      elseif (!array_key_exists($name, $values)) {
-        $entity->get($name)->applyDefaultValue();
-      }
-      unset($values[$name]);
-    }
-
-    // Set any passed values for non-defined fields also.
-    foreach ($values as $name => $value) {
-      $entity->$name = $value;
-    }
-    $entity->postCreate($this);
-
-    // Modules might need to add or change the data initially held by the new
-    // entity object, for instance to fill-in default values.
-    $this->invokeHook('create', $entity);
-
-    return $entity;
-  }
-
-  /**
-   * Builds an entity query.
-   *
-   * @param \Drupal\Core\Entity\Query\QueryInterface $entity_query
-   *   EntityQuery instance.
-   * @param array $values
-   *   An associative array of properties of the entity, where the keys are the
-   *   property names and the values are the values those properties must have.
-   */
-  protected function buildPropertyQuery(QueryInterface $entity_query, array $values) {
-    if ($this->dataTable) {
-      // @todo We should not be using a condition to specify whether conditions
-      //   apply to the default language. See http://drupal.org/node/1866330.
-      // Default to the original entity language if not explicitly specified
-      // otherwise.
-      if (!array_key_exists('default_langcode', $values)) {
-        $values['default_langcode'] = 1;
-      }
-      // If the 'default_langcode' flag is explicitly not set, we do not care
-      // whether the queried values are in the original entity language or not.
-      elseif ($values['default_langcode'] === NULL) {
-        unset($values['default_langcode']);
-      }
-    }
-
-    parent::buildPropertyQuery($entity_query, $values);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  protected function buildQuery($ids, $revision_id = FALSE) {
-    $query = $this->database->select($this->entityInfo['base_table'], 'base');
-    $is_revision_query = $this->revisionKey && ($revision_id || !$this->dataTable);
-
-    $query->addTag($this->entityType . '_load_multiple');
-
-    if ($revision_id) {
-      $query->join($this->revisionTable, 'revision', "revision.{$this->idKey} = base.{$this->idKey} AND revision.{$this->revisionKey} = :revisionId", array(':revisionId' => $revision_id));
-    }
-    elseif ($is_revision_query) {
-      $query->join($this->revisionTable, 'revision', "revision.{$this->revisionKey} = base.{$this->revisionKey}");
-    }
-
-    // Add fields from the {entity} table.
-    $entity_fields = drupal_schema_fields_sql($this->entityInfo['base_table']);
-
-    if ($is_revision_query) {
-      // Add all fields from the {entity_revision} table.
-      $entity_revision_fields = drupal_map_assoc(drupal_schema_fields_sql($this->entityInfo['revision_table']));
-      // The ID field is provided by entity, so remove it.
-      unset($entity_revision_fields[$this->idKey]);
-
-      // Remove all fields from the base table that are also fields by the same
-      // name in the revision table.
-      $entity_field_keys = array_flip($entity_fields);
-      foreach ($entity_revision_fields as $name) {
-        if (isset($entity_field_keys[$name])) {
-          unset($entity_fields[$entity_field_keys[$name]]);
-        }
-      }
-      $query->fields('revision', $entity_revision_fields);
-
-      // Compare revision ID of the base and revision table, if equal then this
-      // is the default revision.
-      $query->addExpression('base.' . $this->revisionKey . ' = revision.' . $this->revisionKey, 'isDefaultRevision');
-    }
-
-    $query->fields('base', $entity_fields);
-
-    if ($ids) {
-      $query->condition("base.{$this->idKey}", $ids, 'IN');
-    }
-
-    return $query;
-  }
-
-  /**
-   * Overrides DatabaseStorageController::attachLoad().
-   *
-   * Added mapping from storage records to entities.
-   */
-  protected function attachLoad(&$queried_entities, $load_revision = FALSE) {
-    // Map the loaded stdclass records into entity objects and according fields.
-    $queried_entities = $this->mapFromStorageRecords($queried_entities, $load_revision);
-    parent::attachLoad($queried_entities, $load_revision);
-  }
-
-  /**
-   * Maps from storage records to entity objects.
-   *
-   * @param array $records
-   *   Associative array of query results, keyed on the entity ID.
-   * @param boolean $load_revision
-   *   (optional) TRUE if the revision should be loaded, defaults to FALSE.
-   *
-   * @return array
-   *   An array of entity objects implementing the EntityInterface.
-   */
-  protected function mapFromStorageRecords(array $records, $load_revision = FALSE) {
-    $entities = array();
-    foreach ($records as $id => $record) {
-      $entities[$id] = array();
-      foreach ($record as $name => $value) {
-        // Skip the item delta and item value levels but let the field assign
-        // the value as suiting. This avoids unnecessary array hierarchies and
-        // saves memory here.
-        $entities[$id][$name][Language::LANGCODE_DEFAULT] = $value;
-      }
-      // If we have no multilingual values we can instantiate entity objecs
-      // right now, otherwise we need to collect all the field values first.
-      if (!$this->dataTable) {
-        $bundle = $this->bundleKey ? $record->{$this->bundleKey} : FALSE;
-        // Turn the record into an entity class.
-        $entities[$id] = new $this->entityClass($entities[$id], $this->entityType, $bundle);
-      }
-    }
-    $this->attachPropertyData($entities, $load_revision);
-    return $entities;
-  }
-
-  /**
-   * Attaches property data in all languages for translatable properties.
-   *
-   * @param array &$entities
-   *   Associative array of entities, keyed on the entity ID.
-   * @param int $revision_id
-   *   (optional) The revision to be loaded. Defaults to FALSE.
-   */
-  protected function attachPropertyData(array &$entities, $revision_id = FALSE) {
-    if ($this->dataTable) {
-      // If a revision table is available, we need all the properties of the
-      // latest revision. Otherwise we fall back to the data table.
-      $table = $this->revisionTable ?: $this->dataTable;
-      $query = $this->database->select($table, 'data', array('fetch' => \PDO::FETCH_ASSOC))
-        ->fields('data')
-        ->condition($this->idKey, array_keys($entities))
-        ->orderBy('data.' . $this->idKey);
-
-      if ($this->revisionTable) {
-        if ($revision_id) {
-          $query->condition($this->revisionKey, $revision_id);
-        }
-        else {
-          // Get the revision IDs.
-          $revision_ids = array();
-          foreach ($entities as $values) {
-            $revision_ids[] = $values[$this->revisionKey];
-          }
-          $query->condition($this->revisionKey, $revision_ids);
-        }
-      }
-
-      $data = $query->execute();
-      $field_definition = \Drupal::entityManager()->getFieldDefinitions($this->entityType);
-      $translations = array();
-      if ($this->revisionTable) {
-        $data_fields = array_flip(array_diff(drupal_schema_fields_sql($this->entityInfo['revision_table']), drupal_schema_fields_sql($this->entityInfo['base_table'])));
-      }
-      else {
-        $data_fields = array_flip(drupal_schema_fields_sql($this->entityInfo['data_table']));
-      }
-
-      foreach ($data as $values) {
-        $id = $values[$this->idKey];
-
-        // Field values in default language are stored with
-        // Language::LANGCODE_DEFAULT as key.
-        $langcode = empty($values['default_langcode']) ? $values['langcode'] : Language::LANGCODE_DEFAULT;
-        $translations[$id][$langcode] = TRUE;
-
-        foreach ($field_definition as $name => $definition) {
-          // Set only translatable properties, unless we are dealing with a
-          // revisable entity, in which case we did not load the untranslatable
-          // data before.
-          $translatable = !empty($definition['translatable']);
-          if (isset($data_fields[$name]) && ($this->revisionTable || $translatable)) {
-            $entities[$id][$name][$langcode] = $values[$name];
-          }
-        }
-      }
-
-      foreach ($entities as $id => $values) {
-        $bundle = $this->bundleKey ? $values[$this->bundleKey][Language::LANGCODE_DEFAULT] : FALSE;
-        // Turn the record into an entity class.
-        $entities[$id] = new $this->entityClass($values, $this->entityType, $bundle, array_keys($translations[$id]));
-      }
-    }
-  }
-
-  /**
-   * Overrides DatabaseStorageController::save().
-   *
-   * Added mapping from entities to storage records before saving.
-   */
-  public function save(EntityInterface $entity) {
-    $transaction = $this->database->startTransaction();
-    try {
-      // Sync the changes made in the fields array to the internal values array.
-      $entity->updateOriginalValues();
-
-      // Load the stored entity, if any.
-      if (!$entity->isNew() && !isset($entity->original)) {
-        $entity->original = entity_load_unchanged($this->entityType, $entity->id());
-      }
-
-      $entity->preSave($this);
-      $this->invokeFieldMethod('preSave', $entity);
-      $this->invokeHook('presave', $entity);
-
-      // Create the storage record to be saved.
-      $record = $this->mapToStorageRecord($entity);
-
-      if (!$entity->isNew()) {
-        if ($entity->isDefaultRevision()) {
-          $return = drupal_write_record($this->entityInfo['base_table'], $record, $this->idKey);
-        }
-        else {
-          // @todo, should a different value be returned when saving an entity
-          // with $isDefaultRevision = FALSE?
-          $return = FALSE;
-        }
-        if ($this->revisionKey) {
-          $record->{$this->revisionKey} = $this->saveRevision($entity);
-        }
-        if ($this->dataTable) {
-          $this->savePropertyData($entity);
-        }
-        $this->resetCache(array($entity->id()));
-        $entity->postSave($this, TRUE);
-        $this->invokeFieldMethod('update', $entity);
-        $this->saveFieldItems($entity, TRUE);
-        $this->invokeHook('update', $entity);
-        if ($this->dataTable) {
-          $this->invokeTranslationHooks($entity);
-        }
-      }
-      else {
-        $return = drupal_write_record($this->entityInfo['base_table'], $record);
-        $entity->{$this->idKey}->value = $record->{$this->idKey};
-        if ($this->revisionKey) {
-          $record->{$this->revisionKey} = $this->saveRevision($entity);
-        }
-        $entity->{$this->idKey}->value = $record->{$this->idKey};
-        if ($this->dataTable) {
-          $this->savePropertyData($entity);
-        }
-
-        // Reset general caches, but keep caches specific to certain entities.
-        $this->resetCache(array());
-
-        $entity->enforceIsNew(FALSE);
-        $entity->postSave($this, FALSE);
-        $this->invokeFieldMethod('insert', $entity);
-        $this->saveFieldItems($entity, FALSE);
-        $this->invokeHook('insert', $entity);
-      }
-
-      // Ignore slave server temporarily.
-      db_ignore_slave();
-      unset($entity->original);
-
-      return $return;
-    }
-    catch (\Exception $e) {
-      $transaction->rollback();
-      watchdog_exception($this->entityType, $e);
-      throw new EntityStorageException($e->getMessage(), $e->getCode(), $e);
-    }
-  }
-
-  /**
-   * Saves an entity revision.
-   *
-   * @param \Drupal\Core\Entity\EntityInterface $entity
-   *   The entity object.
-   *
-   * @return integer
-   *   The revision id.
-   */
-  protected function saveRevision(EntityInterface $entity) {
-    $return = $entity->id();
-    $default_langcode = $entity->getUntranslated()->language()->id;
-
-    if (!$entity->isNewRevision()) {
-      // Delete to handle removed values.
-      $this->database->delete($this->revisionTable)
-        ->condition($this->idKey, $entity->id())
-        ->condition($this->revisionKey, $entity->getRevisionId())
-        ->execute();
-    }
-
-    $languages = $this->dataTable ? $entity->getTranslationLanguages() : array($default_langcode => $entity->language());
-    foreach ($languages as $langcode => $language) {
-      $translation = $entity->getTranslation($langcode);
-      $record = $this->mapToRevisionStorageRecord($translation);
-      $record->langcode = $langcode;
-      $record->default_langcode = $langcode == $default_langcode;
-
-      // When saving a new revision, set any existing revision ID to NULL so as
-      // to ensure that a new revision will actually be created.
-      if ($entity->isNewRevision() && isset($record->{$this->revisionKey})) {
-        $record->{$this->revisionKey} = NULL;
-      }
-
-      $entity->preSaveRevision($this, $record);
-
-      if ($entity->isNewRevision()) {
-        drupal_write_record($this->revisionTable, $record);
-        if ($entity->isDefaultRevision()) {
-          $this->database->update($this->entityInfo['base_table'])
-            ->fields(array($this->revisionKey => $record->{$this->revisionKey}))
-            ->condition($this->idKey, $record->{$this->idKey})
-            ->execute();
-        }
-        $entity->setNewRevision(FALSE);
-      }
-      else {
-        // @todo Use multiple insertions to improve performance.
-        drupal_write_record($this->revisionTable, $record);
-      }
-
-      // Make sure to update the new revision key for the entity.
-      $entity->{$this->revisionKey}->value = $record->{$this->revisionKey};
-      $return = $record->{$this->revisionKey};
-    }
-
-    return $return;
-  }
-
-  /**
-   * Stores the entity property language-aware data.
-   *
-   * @param \Drupal\Core\Entity\EntityInterface $entity
-   *   The entity object.
-   */
-  protected function savePropertyData(EntityInterface $entity) {
-    // Delete and insert to handle removed values.
-    $this->database->delete($this->dataTable)
-      ->condition($this->idKey, $entity->id())
-      ->execute();
-
-    $query = $this->database->insert($this->dataTable);
-
-    foreach ($entity->getTranslationLanguages() as $langcode => $language) {
-      $record = $this->mapToDataStorageRecord($entity, $langcode);
-      $values = (array) $record;
-      $query
-        ->fields(array_keys($values))
-        ->values($values);
-    }
-
-    $query->execute();
-  }
-
-  /**
-   * Maps from an entity object to the storage record of the base table.
-   *
-   * @param \Drupal\Core\Entity\EntityInterface $entity
-   *   The entity object.
-   *
-   * @return \stdClass
-   *   The record to store.
-   */
-  protected function mapToStorageRecord(EntityInterface $entity) {
-    $record = new \stdClass();
-    foreach (drupal_schema_fields_sql($this->entityInfo['base_table']) as $name) {
-      $record->$name = $entity->$name->value;
-    }
-    return $record;
-  }
-
-  /**
-   * Maps from an entity object to the storage record of the revision table.
-   *
-   * @param \Drupal\Core\Entity\EntityInterface $entity
-   *   The entity object.
-   *
-   * @return \stdClass
-   *   The record to store.
-   */
-  protected function mapToRevisionStorageRecord(EntityInterface $entity) {
-    $record = new \stdClass();
-    $definitions = $entity->getPropertyDefinitions();
-    foreach (drupal_schema_fields_sql($this->entityInfo['revision_table']) as $name) {
-      if (isset($definitions[$name]) && isset($entity->$name->value)) {
-        $record->$name = $entity->$name->value;
-      }
-    }
-    return $record;
-  }
-
-  /**
-   * Maps from an entity object to the storage record of the data table.
-   *
-   * @param \Drupal\Core\Entity\EntityInterface $entity
-   *   The entity object.
-   * @param $langcode
-   *   The language code of the translation to get.
-   *
-   * @return \stdClass
-   *   The record to store.
-   */
-  protected function mapToDataStorageRecord(EntityInterface $entity, $langcode) {
-    $default_langcode = $entity->getUntranslated()->language()->id;
-    // Don't use strict mode, this way there's no need to do checks here, as
-    // non-translatable properties are replicated for each language.
-    $translation = $entity->getTranslation($langcode);
-    $definitions = $translation->getPropertyDefinitions();
-    $schema = drupal_get_schema($this->entityInfo['data_table']);
-
-    $record = new \stdClass();
-    foreach (drupal_schema_fields_sql($this->entityInfo['data_table']) as $name) {
-      $info = $schema['fields'][$name];
-      $value = isset($definitions[$name]) && isset($translation->$name->value) ? $translation->$name->value : NULL;
-      $record->$name = drupal_schema_get_field_value($info, $value);
-    }
-    $record->langcode = $langcode;
-    $record->default_langcode = intval($default_langcode == $langcode);
-
-    return $record;
-  }
-
-  /**
-   * Overwrites \Drupal\Core\Entity\DatabaseStorageController::delete().
-   */
-  public function delete(array $entities) {
-    if (!$entities) {
-      // If no IDs or invalid IDs were passed, do nothing.
-      return;
-    }
-
-    $transaction = $this->database->startTransaction();
-    try {
-      $entity_class = $this->entityClass;
-      $entity_class::preDelete($this, $entities);
-
-      foreach ($entities as $entity) {
-        $this->invokeHook('predelete', $entity);
-      }
-      $ids = array_keys($entities);
-
-      $this->database->delete($this->entityInfo['base_table'])
-        ->condition($this->idKey, $ids)
-        ->execute();
-
-      if ($this->revisionKey) {
-        $this->database->delete($this->revisionTable)
-          ->condition($this->idKey, $ids)
-          ->execute();
-      }
-
-      if ($this->dataTable) {
-        $this->database->delete($this->dataTable)
-          ->condition($this->idKey, $ids)
-          ->execute();
-      }
-
-      // Reset the cache as soon as the changes have been applied.
-      $this->resetCache($ids);
-
-      $entity_class::postDelete($this, $entities);
-      foreach ($entities as $entity) {
-        $this->invokeFieldMethod('delete', $entity);
-        $this->deleteFieldItems($entity);
-        $this->invokeHook('delete', $entity);
-      }
-      // Ignore slave server temporarily.
-      db_ignore_slave();
-    }
-    catch (\Exception $e) {
-      $transaction->rollback();
-      watchdog_exception($this->entityType, $e);
-      throw new EntityStorageException($e->getMessage(), $e->getCode(), $e);
-    }
-  }
-}
diff --git a/core/lib/Drupal/Core/Entity/EntityStorageControllerBase.php b/core/lib/Drupal/Core/Entity/EntityStorageControllerBase.php
index 43ff5f1..7d32da8 100644
--- a/core/lib/Drupal/Core/Entity/EntityStorageControllerBase.php
+++ b/core/lib/Drupal/Core/Entity/EntityStorageControllerBase.php
@@ -137,104 +137,6 @@ protected function cacheSet($entities) {
   }
 
   /**
-   * {@inheritdoc}
-   */
-  public function invokeFieldMethod($method, EntityInterface $entity) {
-    foreach (array_keys($entity->getTranslationLanguages()) as $langcode) {
-      // @todo getTranslation() only works on NG entities. Remove the condition
-      // and the second code branch when all core entity types are converted.
-      if ($translation = $entity->getTranslation($langcode)) {
-        foreach ($translation as $field) {
-          $field->$method();
-        }
-      }
-      else {
-        // For BC entities, iterate through fields and instantiate NG items
-        // objects manually.
-        $definitions = \Drupal::entityManager()->getFieldDefinitions($entity->entityType(), $entity->bundle());
-        foreach ($definitions as $field_name => $definition) {
-          if (!empty($definition['configurable'])) {
-            // Create the items object.
-            $itemsBC = isset($entity->{$field_name}[$langcode]) ? $entity->{$field_name}[$langcode] : array();
-            // @todo Exception : this calls setValue(), tries to set the
-            // 'formatted' property. For now, this is worked around by
-            // commenting out the Exception in TextProcessed::setValue().
-            $items = \Drupal::typedData()->create($definition, $itemsBC, $field_name, $entity);
-            $items->$method();
-
-            // Put back the items values in the entity.
-            $itemsBC = $items->getValue(TRUE);
-            if ($itemsBC !== array() || isset($entity->{$field_name}[$langcode])) {
-              $entity->{$field_name}[$langcode] = $itemsBC;
-            }
-          }
-        }
-      }
-    }
-  }
-
-   /**
-   * {@inheritdoc}
-   */
-  public function invokeFieldItemPrepareCache(EntityInterface $entity) {
-    foreach (array_keys($entity->getTranslationLanguages()) as $langcode) {
-      // @todo getTranslation() only works on NG entities. Remove the condition
-      // and the second code branch when all core entity types are converted.
-      if ($translation = $entity->getTranslation($langcode)) {
-        foreach ($translation->getPropertyDefinitions() as $property => $definition) {
-          $type_definition = \Drupal::typedData()->getDefinition($definition['type']);
-          // Only create the item objects if needed.
-          if (is_subclass_of($type_definition['class'], '\Drupal\Core\Entity\Field\PrepareCacheInterface')
-            // Prevent legacy field types from skewing performance too much by
-            // checking the existence of the legacy function directly, instead
-            // of making LegacyConfigFieldItem implement PrepareCacheInterface.
-            // @todo Remove once all core field types have been converted (see
-            // http://drupal.org/node/2014671).
-            || (is_subclass_of($type_definition['class'], '\Drupal\field\Plugin\field\field_type\LegacyConfigFieldItem')
-              && isset($type_definition['provider']) && function_exists($type_definition['provider'] . '_field_load'))) {
-
-            // Call the prepareCache() method directly on each item
-            // individually.
-            foreach ($translation->get($property) as $item) {
-              $item->prepareCache();
-            }
-          }
-        }
-      }
-      else {
-        // For BC entities, iterate through the fields and instantiate NG items
-        // objects manually.
-        $definitions = \Drupal::entityManager()->getFieldDefinitions($entity->entityType(), $entity->bundle());
-        foreach ($definitions as $field_name => $definition) {
-          if (!empty($definition['configurable'])) {
-            $type_definition = \Drupal::typedData()->getDefinition($definition['type']);
-            // Only create the item objects if needed.
-            if (is_subclass_of($type_definition['class'], '\Drupal\Core\Entity\Field\PrepareCacheInterface')
-              // @todo Remove once all core field types have been converted
-              // (see http://drupal.org/node/2014671).
-              || (is_subclass_of($type_definition['class'], '\Drupal\field\Plugin\field\field_type\LegacyConfigFieldItem') && function_exists($type_definition['provider'] . '_field_load'))) {
-
-              // Create the items object.
-              $items = isset($entity->{$field_name}[$langcode]) ? $entity->{$field_name}[$langcode] : array();
-              $itemsNG = \Drupal::typedData()->create($definition, $items, $field_name, $entity);
-
-              foreach ($itemsNG as $item) {
-                $item->prepareCache();
-              }
-
-              // Put back the items values in the entity.
-              $items = $itemsNG->getValue(TRUE);
-              if ($items !== array() || isset($entity->{$field_name}[$langcode])) {
-                $entity->{$field_name}[$langcode] = $items;
-              }
-            }
-          }
-        }
-      }
-    }
-  }
-
-  /**
    * Invokes a hook on behalf of the entity.
    *
    * @param string $hook
diff --git a/core/lib/Drupal/Core/Entity/EntityStorageControllerInterface.php b/core/lib/Drupal/Core/Entity/EntityStorageControllerInterface.php
index c7f72f7..0a275e9 100644
--- a/core/lib/Drupal/Core/Entity/EntityStorageControllerInterface.php
+++ b/core/lib/Drupal/Core/Entity/EntityStorageControllerInterface.php
@@ -153,22 +153,4 @@ public function save(EntityInterface $entity);
    */
   public function getQueryServicename();
 
-  /**
-   * Invokes a method on the Field objects within an entity.
-   *
-   * @param string $method
-   *   The method name.
-   * @param \Drupal\Core\Entity\EntityInterface $entity
-   *   The entity object.
-   */
-  public function invokeFieldMethod($method, EntityInterface $entity);
-
-  /**
-   * Invokes the prepareCache() method on all the relevant FieldItem objects.
-   *
-   * @param \Drupal\Core\Entity\EntityInterface $entity
-   *   The entity object.
-   */
-  public function invokeFieldItemPrepareCache(EntityInterface $entity);
-
 }
diff --git a/core/lib/Drupal/Core/Entity/DatabaseStorageController.php b/core/lib/Drupal/Core/Entity/FieldableDatabaseStorageController.php
similarity index 76%
copy from core/lib/Drupal/Core/Entity/DatabaseStorageController.php
copy to core/lib/Drupal/Core/Entity/FieldableDatabaseStorageController.php
index 2bed3f6..affb8d6 100644
--- a/core/lib/Drupal/Core/Entity/DatabaseStorageController.php
+++ b/core/lib/Drupal/Core/Entity/FieldableDatabaseStorageController.php
@@ -27,7 +27,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 FieldableEntityStorageControllerBase {
+class FieldableDatabaseStorageController extends FieldableEntityStorageControllerBase {
 
   /**
    * Name of entity's revision database table field, if it supports revisions.
@@ -69,6 +69,20 @@ class DatabaseStorageController extends FieldableEntityStorageControllerBase {
   protected $fieldInfo;
 
   /**
+   * The entity bundle key.
+   *
+   * @var string|bool
+   */
+  protected $bundleKey;
+
+  /**
+   * The table that stores properties, if the entity has multilingual support.
+   *
+   * @var string
+   */
+  protected $dataTable;
+
+  /**
    * {@inheritdoc}
    */
   public static function createInstance(ContainerInterface $container, $entity_type, array $entity_info) {
@@ -97,6 +111,7 @@ public function __construct($entity_type, array $entity_info, Connection $databa
 
     $this->database = $database;
     $this->fieldInfo = $field_info;
+    $this->bundleKey = !empty($this->entityInfo['entity_keys']['bundle']) ? $this->entityInfo['entity_keys']['bundle'] : FALSE;
 
     // Check if the entity type supports IDs.
     if (isset($this->entityInfo['entity_keys']['id'])) {
@@ -122,6 +137,11 @@ public function __construct($entity_type, array $entity_info, Connection $databa
     else {
       $this->revisionKey = FALSE;
     }
+
+    // Check if the entity type has a dedicated table for properties.
+    if (!empty($this->entityInfo['data_table'])) {
+      $this->dataTable = $this->entityInfo['data_table'];
+    }
   }
 
   /**
@@ -152,13 +172,6 @@ public function loadMultiple(array $ids = NULL) {
     if ($ids === NULL || $ids) {
       // Build and execute the query.
       $query_result = $this->buildQuery($ids)->execute();
-
-      if (!empty($this->entityInfo['class'])) {
-        // 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));
-      }
       $queried_entities = $query_result->fetchAllAssoc($this->idKey);
     }
 
@@ -263,6 +276,21 @@ public function loadByProperties(array $values = array()) {
    *   property names and the values are the values those properties must have.
    */
   protected function buildPropertyQuery(QueryInterface $entity_query, array $values) {
+    if ($this->dataTable) {
+      // @todo We should not be using a condition to specify whether conditions
+      //   apply to the default language. See http://drupal.org/node/1866330.
+      // Default to the original entity language if not explicitly specified
+      // otherwise.
+      if (!array_key_exists('default_langcode', $values)) {
+        $values['default_langcode'] = 1;
+      }
+      // If the 'default_langcode' flag is explicitly not set, we do not care
+      // whether the queried values are in the original entity language or not.
+      elseif ($values['default_langcode'] === NULL) {
+        unset($values['default_langcode']);
+      }
+    }
+
     foreach ($values as $name => $value) {
       $entity_query->condition($name, $value);
     }
@@ -290,23 +318,24 @@ protected function buildPropertyQuery(QueryInterface $entity_query, array $value
    */
   protected function buildQuery($ids, $revision_id = FALSE) {
     $query = $this->database->select($this->entityInfo['base_table'], 'base');
+    $is_revision_query = $this->revisionKey && ($revision_id || !$this->dataTable);
 
     $query->addTag($this->entityType . '_load_multiple');
 
     if ($revision_id) {
       $query->join($this->revisionTable, 'revision', "revision.{$this->idKey} = base.{$this->idKey} AND revision.{$this->revisionKey} = :revisionId", array(':revisionId' => $revision_id));
     }
-    elseif ($this->revisionKey) {
+    elseif ($is_revision_query) {
       $query->join($this->revisionTable, 'revision', "revision.{$this->revisionKey} = base.{$this->revisionKey}");
     }
 
     // Add fields from the {entity} table.
     $entity_fields = drupal_schema_fields_sql($this->entityInfo['base_table']);
 
-    if ($this->revisionKey) {
+    if ($is_revision_query) {
       // Add all fields from the {entity_revision} table.
       $entity_revision_fields = drupal_map_assoc(drupal_schema_fields_sql($this->entityInfo['revision_table']));
-      // The id field is provided by entity, so remove it.
+      // The ID field is provided by entity, so remove it.
       unset($entity_revision_fields[$this->idKey]);
 
       // Remove all fields from the base table that are also fields by the same
@@ -319,7 +348,7 @@ protected function buildQuery($ids, $revision_id = FALSE) {
       }
       $query->fields('revision', $entity_revision_fields);
 
-      // Compare revision id of the base and revision table, if equal then this
+      // Compare revision ID of the base and revision table, if equal then this
       // is the default revision.
       $query->addExpression('base.' . $this->revisionKey . ' = revision.' . $this->revisionKey, 'isDefaultRevision');
     }
@@ -350,6 +379,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) {
+    // Map the loaded records into entity objects and according fields.
+    $queried_entities = $this->mapFromStorageRecords($queried_entities, $load_revision);
+
     // Attach field values.
     if ($this->entityInfo['fieldable']) {
       $this->loadFieldItems($queried_entities, $load_revision ? static::FIELD_LOAD_REVISION : static::FIELD_LOAD_CURRENT);
@@ -370,18 +402,35 @@ protected function attachLoad(&$queried_entities, $load_revision = FALSE) {
   }
 
   /**
-   * Implements \Drupal\Core\Entity\EntityStorageControllerInterface::create().
+   * {@inheritdoc}
    */
   public function create(array $values) {
     $entity_class = $this->entityInfo['class'];
     $entity_class::preCreate($this, $values);
 
-    $entity = new $entity_class($values, $this->entityType);
+    // We have to determine the bundle first.
+    $bundle = FALSE;
+    if ($this->bundleKey) {
+      if (!isset($values[$this->bundleKey])) {
+        throw new EntityStorageException(format_string('Missing bundle for entity type @type', array('@type' => $this->entityType)));
+      }
+      $bundle = $values[$this->bundleKey];
+    }
+    $entity = new $entity_class(array(), $this->entityType, $bundle);
+
+    foreach ($entity as $name => $field) {
+      if (isset($values[$name])) {
+        $entity->$name = $values[$name];
+      }
+      elseif (!array_key_exists($name, $values)) {
+        $entity->get($name)->applyDefaultValue();
+      }
+      unset($values[$name]);
+    }
 
-    // Assign a new UUID if there is none yet.
-    if ($this->uuidKey && !isset($entity->{$this->uuidKey})) {
-      $uuid = new Uuid();
-      $entity->{$this->uuidKey} = $uuid->generate();
+    // Set any passed values for non-defined fields also.
+    foreach ($values as $name => $value) {
+      $entity->$name = $value;
     }
     $entity->postCreate($this);
 
@@ -445,6 +494,9 @@ public function delete(array $entities) {
   public function save(EntityInterface $entity) {
     $transaction = $this->database->startTransaction();
     try {
+      // Sync the changes made in the fields array to the internal values array.
+      $entity->updateOriginalValues();
+
       // Load the stored entity, if any.
       if (!$entity->isNew() && !isset($entity->original)) {
         $entity->original = entity_load_unchanged($this->entityType, $entity->id());
@@ -454,9 +506,12 @@ public function save(EntityInterface $entity) {
       $this->invokeFieldMethod('preSave', $entity);
       $this->invokeHook('presave', $entity);
 
+      // Create the storage record to be saved.
+      $record = $this->mapToStorageRecord($entity);
+
       if (!$entity->isNew()) {
         if ($entity->isDefaultRevision()) {
-          $return = drupal_write_record($this->entityInfo['base_table'], $entity, $this->idKey);
+          $return = drupal_write_record($this->entityInfo['base_table'], $record, $this->idKey);
         }
         else {
           // @todo, should a different value be returned when saving an entity
@@ -464,19 +519,31 @@ public function save(EntityInterface $entity) {
           $return = FALSE;
         }
         if ($this->revisionKey) {
-          $this->saveRevision($entity);
+          $record->{$this->revisionKey} = $this->saveRevision($entity);
+        }
+        if ($this->dataTable) {
+          $this->savePropertyData($entity);
         }
         $this->resetCache(array($entity->id()));
         $entity->postSave($this, TRUE);
         $this->invokeFieldMethod('update', $entity);
         $this->saveFieldItems($entity, TRUE);
         $this->invokeHook('update', $entity);
+        if ($this->dataTable) {
+          $this->invokeTranslationHooks($entity);
+        }
       }
       else {
-        $return = drupal_write_record($this->entityInfo['base_table'], $entity);
+        $return = drupal_write_record($this->entityInfo['base_table'], $record);
+        $entity->{$this->idKey}->value = $record->{$this->idKey};
         if ($this->revisionKey) {
-          $this->saveRevision($entity);
+          $record->{$this->revisionKey} = $this->saveRevision($entity);
         }
+        $entity->{$this->idKey}->value = $record->{$this->idKey};
+        if ($this->dataTable) {
+          $this->savePropertyData($entity);
+        }
+
         // Reset general caches, but keep caches specific to certain entities.
         $this->resetCache(array());
 
@@ -500,44 +567,64 @@ public function save(EntityInterface $entity) {
     }
   }
 
+
   /**
    * Saves an entity revision.
    *
    * @param \Drupal\Core\Entity\EntityInterface $entity
    *   The entity object.
+   *
+   * @return integer
+   *   The revision id.
    */
   protected function saveRevision(EntityInterface $entity) {
-    // Convert the entity into an array as it might not have the same properties
-    // as the entity, it is just a raw structure.
-    $record = (array) $entity;
-
-    // When saving a new revision, set any existing revision ID to NULL so as to
-    // ensure that a new revision will actually be created.
-    if ($entity->isNewRevision() && $record[$this->revisionKey]) {
-      $record[$this->revisionKey] = NULL;
+    $return = $entity->id();
+    $default_langcode = $entity->getUntranslated()->language()->id;
+
+    if (!$entity->isNewRevision()) {
+      // Delete to handle removed values.
+      $this->database->delete($this->revisionTable)
+        ->condition($this->idKey, $entity->id())
+        ->condition($this->revisionKey, $entity->getRevisionId())
+        ->execute();
     }
 
-    // Cast to object as preSaveRevision() expects one to be compatible with the
-    // upcoming NG storage controller.
-    $record = (object) $record;
-    $entity->preSaveRevision($this, $record);
-    $record = (array) $record;
-
-    if ($entity->isNewRevision()) {
-      drupal_write_record($this->revisionTable, $record);
-      if ($entity->isDefaultRevision()) {
-        $this->database->update($this->entityInfo['base_table'])
-          ->fields(array($this->revisionKey => $record[$this->revisionKey]))
-          ->condition($this->idKey, $entity->id())
-          ->execute();
+    $languages = $this->dataTable ? $entity->getTranslationLanguages() : array($default_langcode => $entity->language());
+    foreach ($languages as $langcode => $language) {
+      $translation = $entity->getTranslation($langcode);
+      $record = $this->mapToRevisionStorageRecord($translation);
+      $record->langcode = $langcode;
+      $record->default_langcode = $langcode == $default_langcode;
+
+      // When saving a new revision, set any existing revision ID to NULL so as
+      // to ensure that a new revision will actually be created.
+      if ($entity->isNewRevision() && isset($record->{$this->revisionKey})) {
+        $record->{$this->revisionKey} = NULL;
       }
-      $entity->setNewRevision(FALSE);
-    }
-    else {
-      drupal_write_record($this->revisionTable, $record, $this->revisionKey);
+
+      $entity->preSaveRevision($this, $record);
+
+      if ($entity->isNewRevision()) {
+        drupal_write_record($this->revisionTable, $record);
+        if ($entity->isDefaultRevision()) {
+          $this->database->update($this->entityInfo['base_table'])
+            ->fields(array($this->revisionKey => $record->{$this->revisionKey}))
+            ->condition($this->idKey, $record->{$this->idKey})
+            ->execute();
+        }
+        $entity->setNewRevision(FALSE);
+      }
+      else {
+        // @todo Use multiple insertions to improve performance.
+        drupal_write_record($this->revisionTable, $record);
+      }
+
+      // Make sure to update the new revision key for the entity.
+      $entity->{$this->revisionKey}->value = $record->{$this->revisionKey};
+      $return = $record->{$this->revisionKey};
     }
-    // Make sure to update the new revision key for the entity.
-    $entity->{$this->revisionKey} = $record[$this->revisionKey];
+
+    return $return;
   }
 
   /**
@@ -1191,4 +1278,201 @@ static public function _fieldColumnName(FieldInterface $field, $column) {
     return in_array($column, Field::getReservedColumns()) ? $column : $field->getFieldName() . '_' . $column;
   }
 
+  /**
+   * Maps from storage records to entity objects.
+   *
+   * @param array $records
+   *   Associative array of query results, keyed on the entity ID.
+   * @param boolean $load_revision
+   *   (optional) TRUE if the revision should be loaded, defaults to FALSE.
+   *
+   * @return array
+   *   An array of entity objects implementing the EntityInterface.
+   */
+  protected function mapFromStorageRecords(array $records, $load_revision = FALSE) {
+    $entities = array();
+    foreach ($records as $id => $record) {
+      $entities[$id] = array();
+      foreach ($record as $name => $value) {
+        // Skip the item delta and item value levels but let the field assign
+        // the value as suiting. This avoids unnecessary array hierarchies and
+        // saves memory here.
+        $entities[$id][$name][Language::LANGCODE_DEFAULT] = $value;
+      }
+      // If we have no multilingual values we can instantiate entity objecs
+      // right now, otherwise we need to collect all the field values first.
+      if (!$this->dataTable) {
+        $bundle = $this->bundleKey ? $record->{$this->bundleKey} : FALSE;
+        // Turn the record into an entity class.
+        $entity_class = $this->entityInfo['class'];
+        $entities[$id] = new $entity_class($entities[$id], $this->entityType, $bundle);
+      }
+    }
+    $this->attachPropertyData($entities, $load_revision);
+    return $entities;
+  }
+
+  /**
+   * Attaches property data in all languages for translatable properties.
+   *
+   * @param array &$entities
+   *   Associative array of entities, keyed on the entity ID.
+   * @param int $revision_id
+   *   (optional) The revision to be loaded. Defaults to FALSE.
+   */
+  protected function attachPropertyData(array &$entities, $revision_id = FALSE) {
+    if ($this->dataTable) {
+      // If a revision table is available, we need all the properties of the
+      // latest revision. Otherwise we fall back to the data table.
+      $table = $this->revisionTable ?: $this->dataTable;
+      $query = $this->database->select($table, 'data', array('fetch' => \PDO::FETCH_ASSOC))
+        ->fields('data')
+        ->condition($this->idKey, array_keys($entities))
+        ->orderBy('data.' . $this->idKey);
+
+      if ($this->revisionTable) {
+        if ($revision_id) {
+          $query->condition($this->revisionKey, $revision_id);
+        }
+        else {
+          // Get the revision IDs.
+          $revision_ids = array();
+          foreach ($entities as $values) {
+            $revision_ids[] = $values[$this->revisionKey];
+          }
+          $query->condition($this->revisionKey, $revision_ids);
+        }
+      }
+
+      $data = $query->execute();
+      $field_definition = \Drupal::entityManager()->getFieldDefinitions($this->entityType);
+      $translations = array();
+      if ($this->revisionTable) {
+        $data_fields = array_flip(array_diff(drupal_schema_fields_sql($this->entityInfo['revision_table']), drupal_schema_fields_sql($this->entityInfo['base_table'])));
+      }
+      else {
+        $data_fields = array_flip(drupal_schema_fields_sql($this->entityInfo['data_table']));
+      }
+
+      foreach ($data as $values) {
+        $id = $values[$this->idKey];
+
+        // Field values in default language are stored with
+        // Language::LANGCODE_DEFAULT as key.
+        $langcode = empty($values['default_langcode']) ? $values['langcode'] : Language::LANGCODE_DEFAULT;
+        $translations[$id][$langcode] = TRUE;
+
+        foreach ($field_definition as $name => $definition) {
+          // Set only translatable properties, unless we are dealing with a
+          // revisable entity, in which case we did not load the untranslatable
+          // data before.
+          $translatable = !empty($definition['translatable']);
+          if (isset($data_fields[$name]) && ($this->revisionTable || $translatable)) {
+            $entities[$id][$name][$langcode] = $values[$name];
+          }
+        }
+      }
+
+      foreach ($entities as $id => $values) {
+        $bundle = $this->bundleKey ? $values[$this->bundleKey][Language::LANGCODE_DEFAULT] : FALSE;
+        // Turn the record into an entity class.
+        $entity_class = $this->entityInfo['class'];
+        $entities[$id] = new $entity_class($values, $this->entityType, $bundle, array_keys($translations[$id]));
+      }
+    }
+  }
+
+  /**
+   * Stores the entity property language-aware data.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $entity
+   *   The entity object.
+   */
+  protected function savePropertyData(EntityInterface $entity) {
+    // Delete and insert to handle removed values.
+    $this->database->delete($this->dataTable)
+      ->condition($this->idKey, $entity->id())
+      ->execute();
+
+    $query = $this->database->insert($this->dataTable);
+
+    foreach ($entity->getTranslationLanguages() as $langcode => $language) {
+      $record = $this->mapToDataStorageRecord($entity, $langcode);
+      $values = (array) $record;
+      $query
+        ->fields(array_keys($values))
+        ->values($values);
+    }
+
+    $query->execute();
+  }
+
+  /**
+   * Maps from an entity object to the storage record of the base table.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $entity
+   *   The entity object.
+   *
+   * @return \stdClass
+   *   The record to store.
+   */
+  protected function mapToStorageRecord(EntityInterface $entity) {
+    $record = new \stdClass();
+    foreach (drupal_schema_fields_sql($this->entityInfo['base_table']) as $name) {
+      $record->$name = $entity->$name->value;
+    }
+    return $record;
+  }
+
+  /**
+   * Maps from an entity object to the storage record of the revision table.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $entity
+   *   The entity object.
+   *
+   * @return \stdClass
+   *   The record to store.
+   */
+  protected function mapToRevisionStorageRecord(EntityInterface $entity) {
+    $record = new \stdClass();
+    $definitions = $entity->getPropertyDefinitions();
+    foreach (drupal_schema_fields_sql($this->entityInfo['revision_table']) as $name) {
+      if (isset($definitions[$name]) && isset($entity->$name->value)) {
+        $record->$name = $entity->$name->value;
+      }
+    }
+    return $record;
+  }
+
+  /**
+   * Maps from an entity object to the storage record of the data table.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $entity
+   *   The entity object.
+   * @param $langcode
+   *   The language code of the translation to get.
+   *
+   * @return \stdClass
+   *   The record to store.
+   */
+  protected function mapToDataStorageRecord(EntityInterface $entity, $langcode) {
+    $default_langcode = $entity->getUntranslated()->language()->id;
+    // Don't use strict mode, this way there's no need to do checks here, as
+    // non-translatable properties are replicated for each language.
+    $translation = $entity->getTranslation($langcode);
+    $definitions = $translation->getPropertyDefinitions();
+    $schema = drupal_get_schema($this->entityInfo['data_table']);
+
+    $record = new \stdClass();
+    foreach (drupal_schema_fields_sql($this->entityInfo['data_table']) as $name) {
+      $info = $schema['fields'][$name];
+      $value = isset($definitions[$name]) && isset($translation->$name->value) ? $translation->$name->value : NULL;
+      $record->$name = drupal_schema_get_field_value($info, $value);
+    }
+    $record->langcode = $langcode;
+    $record->default_langcode = intval($default_langcode == $langcode);
+
+    return $record;
+  }
+
 }
diff --git a/core/lib/Drupal/Core/Entity/FieldableEntityStorageControllerBase.php b/core/lib/Drupal/Core/Entity/FieldableEntityStorageControllerBase.php
index 87b86c0..aa9e589 100644
--- a/core/lib/Drupal/Core/Entity/FieldableEntityStorageControllerBase.php
+++ b/core/lib/Drupal/Core/Entity/FieldableEntityStorageControllerBase.php
@@ -293,4 +293,45 @@ public function onFieldItemsPurge(EntityInterface $entity, FieldInstanceInterfac
    */
   public function onFieldPurge(FieldInterface $field) { }
 
+
+  /**
+   * {@inheritdoc}
+   */
+  public function invokeFieldMethod($method, EntityInterface $entity) {
+    foreach (array_keys($entity->getTranslationLanguages()) as $langcode) {
+      $translation = $entity->getTranslation($langcode);
+      foreach ($translation as $field) {
+        $field->$method();
+      }
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function invokeFieldItemPrepareCache(EntityInterface $entity) {
+    foreach (array_keys($entity->getTranslationLanguages()) as $langcode) {
+      $translation = $entity->getTranslation($langcode);
+      foreach ($translation->getPropertyDefinitions() as $property => $definition) {
+        $type_definition = \Drupal::typedData()->getDefinition($definition['type']);
+        // Only create the item objects if needed.
+        if (is_subclass_of($type_definition['class'], '\Drupal\Core\Entity\Field\PrepareCacheInterface')
+          // Prevent legacy field types from skewing performance too much by
+          // checking the existence of the legacy function directly, instead
+          // of making LegacyConfigFieldItem implement PrepareCacheInterface.
+          // @todo Remove once all core field types have been converted (see
+          // http://drupal.org/node/2014671).
+          || (is_subclass_of($type_definition['class'], '\Drupal\field\Plugin\field\field_type\LegacyConfigFieldItem')
+            && isset($type_definition['provider']) && function_exists($type_definition['provider'] . '_field_load'))) {
+
+          // Call the prepareCache() method directly on each item
+          // individually.
+          foreach ($translation->get($property) as $item) {
+            $item->prepareCache();
+          }
+        }
+      }
+    }
+  }
+
 }
diff --git a/core/lib/Drupal/Core/Entity/FieldableEntityStorageControllerInterface.php b/core/lib/Drupal/Core/Entity/FieldableEntityStorageControllerInterface.php
index 31d59ab..0719117 100644
--- a/core/lib/Drupal/Core/Entity/FieldableEntityStorageControllerInterface.php
+++ b/core/lib/Drupal/Core/Entity/FieldableEntityStorageControllerInterface.php
@@ -117,4 +117,22 @@ public function onFieldItemsPurge(EntityInterface $entity, FieldInstanceInterfac
    */
   public function onFieldPurge(FieldInterface $field);
 
+  /**
+   * Invokes a method on the Field objects within an entity.
+   *
+   * @param string $method
+   *   The method name.
+   * @param \Drupal\Core\Entity\EntityInterface $entity
+   *   The entity object.
+   */
+  public function invokeFieldMethod($method, EntityInterface $entity);
+
+  /**
+   * Invokes the prepareCache() method on all the relevant FieldItem objects.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $entity
+   *   The entity object.
+   */
+  public function invokeFieldItemPrepareCache(EntityInterface $entity);
+
 }
diff --git a/core/lib/Drupal/Core/Entity/Query/Sql/Tables.php b/core/lib/Drupal/Core/Entity/Query/Sql/Tables.php
index 9607dd1..1593cce 100644
--- a/core/lib/Drupal/Core/Entity/Query/Sql/Tables.php
+++ b/core/lib/Drupal/Core/Entity/Query/Sql/Tables.php
@@ -9,7 +9,7 @@
 
 use Drupal\Core\Database\Query\SelectInterface;
 use Drupal\Core\Entity\EntityStorageControllerInterface;
-use Drupal\Core\Entity\DatabaseStorageController;
+use Drupal\Core\Entity\FieldableDatabaseStorageController;
 use Drupal\Core\Entity\Plugin\DataType\EntityReference;
 use Drupal\Core\Entity\Query\QueryException;
 use Drupal\field\Entity\Field;
@@ -162,7 +162,7 @@ public 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 = DatabaseStorageController::_fieldColumnName($field, $column);
+        $sql_column = FieldableDatabaseStorageController::_fieldColumnName($field, $column);
       }
       // This is an entity property (non-configurable field).
       else {
@@ -250,7 +250,7 @@ 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') == EntityStorageControllerInterface::FIELD_LOAD_CURRENT ? DatabaseStorageController::_fieldTableName($field) : DatabaseStorageController::_fieldRevisionTableName($field);
+      $table = $this->sqlQuery->getMetaData('age') == EntityStorageControllerInterface::FIELD_LOAD_CURRENT ? FieldableDatabaseStorageController::_fieldTableName($field) : FieldableDatabaseStorageController::_fieldRevisionTableName($field);
       if ($field['cardinality'] != 1) {
         $this->sqlQuery->addMetaData('simple_query', FALSE);
       }
diff --git a/core/modules/aggregator/lib/Drupal/aggregator/FeedStorageController.php b/core/modules/aggregator/lib/Drupal/aggregator/FeedStorageController.php
index 6db9b3f..17ea1e2 100644
--- a/core/modules/aggregator/lib/Drupal/aggregator/FeedStorageController.php
+++ b/core/modules/aggregator/lib/Drupal/aggregator/FeedStorageController.php
@@ -7,7 +7,7 @@
 
 namespace Drupal\aggregator;
 
-use Drupal\Core\Entity\DatabaseStorageControllerNG;
+use Drupal\Core\Entity\FieldableDatabaseStorageController;
 use Drupal\aggregator\Entity\Feed;
 use Drupal\Core\Entity\EntityInterface;
 
@@ -17,7 +17,7 @@
  * This extends the Drupal\Core\Entity\DatabaseStorageController class, adding
  * required special handling for feed entities.
  */
-class FeedStorageController extends DatabaseStorageControllerNG implements FeedStorageControllerInterface {
+class FeedStorageController extends FieldableDatabaseStorageController implements FeedStorageControllerInterface {
 
   /**
    * Overrides Drupal\Core\Entity\DataBaseStorageController::attachLoad().
diff --git a/core/modules/aggregator/lib/Drupal/aggregator/ItemStorageController.php b/core/modules/aggregator/lib/Drupal/aggregator/ItemStorageController.php
index e17c82b..7e05027 100644
--- a/core/modules/aggregator/lib/Drupal/aggregator/ItemStorageController.php
+++ b/core/modules/aggregator/lib/Drupal/aggregator/ItemStorageController.php
@@ -10,7 +10,7 @@
 use Drupal\aggregator\Entity\Item;
 use Drupal\Core\Database\Query\PagerSelectExtender;
 use Drupal\Core\Database\Query\SelectInterface;
-use Drupal\Core\Entity\DatabaseStorageControllerNG;
+use Drupal\Core\Entity\FieldableDatabaseStorageController;
 
 /**
  * Controller class for aggregators items.
@@ -18,7 +18,7 @@
  * This extends the Drupal\Core\Entity\DatabaseStorageController class, adding
  * required special handling for feed item entities.
  */
-class ItemStorageController extends DatabaseStorageControllerNG implements ItemStorageControllerInterface {
+class ItemStorageController extends FieldableDatabaseStorageController implements ItemStorageControllerInterface {
 
   /**
    * Overrides Drupal\Core\Entity\DataBaseStorageController::attachLoad().
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 9c5eb21..2078f58 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
@@ -7,16 +7,16 @@
 
 namespace Drupal\custom_block;
 
-use Drupal\Core\Entity\DatabaseStorageControllerNG;
+use Drupal\Core\Entity\FieldableDatabaseStorageController;
 use Drupal\Core\Entity\EntityStorageControllerInterface;
 
 /**
  * Controller class for custom blocks.
  *
- * This extends the Drupal\Core\Entity\DatabaseStorageControllerNG class,
+ * This extends the Drupal\Core\Entity\DatabaseStorageController class,
  * adding required special handling for custom block entities.
  */
-class CustomBlockStorageController extends DatabaseStorageControllerNG {
+class CustomBlockStorageController extends FieldableDatabaseStorageController {
 
   /**
    * Overrides \Drupal\Core\Entity\DatabaseStorageController::attachLoad().
diff --git a/core/modules/comment/lib/Drupal/comment/CommentStorageController.php b/core/modules/comment/lib/Drupal/comment/CommentStorageController.php
index 6068ce9..cbf316b 100644
--- a/core/modules/comment/lib/Drupal/comment/CommentStorageController.php
+++ b/core/modules/comment/lib/Drupal/comment/CommentStorageController.php
@@ -8,7 +8,7 @@
 namespace Drupal\comment;
 
 use Drupal\Core\Entity\EntityInterface;
-use Drupal\Core\Entity\DatabaseStorageControllerNG;
+use Drupal\Core\Entity\FieldableDatabaseStorageController;
 use Drupal\Component\Uuid\Uuid;
 
 /**
@@ -17,7 +17,7 @@
  * This extends the Drupal\Core\Entity\DatabaseStorageController class, adding
  * required special handling for comment entities.
  */
-class CommentStorageController extends DatabaseStorageControllerNG implements CommentStorageControllerInterface {
+class CommentStorageController extends FieldableDatabaseStorageController implements CommentStorageControllerInterface {
 
   /**
    * The thread for which a lock was acquired.
diff --git a/core/modules/contact/lib/Drupal/contact/Entity/Message.php b/core/modules/contact/lib/Drupal/contact/Entity/Message.php
index 0c3c622..be1d34a 100644
--- a/core/modules/contact/lib/Drupal/contact/Entity/Message.php
+++ b/core/modules/contact/lib/Drupal/contact/Entity/Message.php
@@ -20,7 +20,7 @@
  *   label = @Translation("Contact message"),
  *   module = "contact",
  *   controllers = {
- *     "storage" = "Drupal\Core\Entity\DatabaseStorageControllerNG",
+ *     "storage" = "Drupal\Core\Entity\DatabaseStorageController",
  *     "render" = "Drupal\contact\MessageRenderController",
  *     "form" = {
  *       "default" = "Drupal\contact\MessageFormController"
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 650a216..709449c 100644
--- a/core/modules/contact/lib/Drupal/contact/Tests/Views/ContactFieldsTest.php
+++ b/core/modules/contact/lib/Drupal/contact/Tests/Views/ContactFieldsTest.php
@@ -7,7 +7,7 @@
 
 namespace Drupal\contact\Tests\Views;
 
-use Drupal\Core\Entity\DatabaseStorageController;
+use Drupal\Core\Entity\FieldableDatabaseStorageController;
 use Drupal\views\Tests\ViewTestBase;
 
 /**
@@ -62,7 +62,7 @@ protected function setUp() {
   public function testViewsData() {
     // Test that the field is not exposed to views, since contact_message
     // entities have no storage.
-    $table_name = DatabaseStorageController::_fieldTableName($this->field);
+    $table_name = FieldableDatabaseStorageController::_fieldTableName($this->field);
     $data = $this->container->get('views.views_data')->get($table_name);
     $this->assertFalse($data, 'The field is not exposed to Views.');
   }
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 b43d921..8bd4876 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
@@ -7,7 +7,7 @@
 
 namespace Drupal\content_translation\Tests;
 
-use Drupal\Core\Entity\DatabaseStorageControllerNG;
+use Drupal\Core\Entity\FieldableDatabaseStorageController;
 use Drupal\Core\Language\Language;
 use Drupal\simpletest\WebTestBase;
 
@@ -204,7 +204,7 @@ protected function createEntity($values, $langcode, $bundle_name = NULL) {
       $entity_values[$info['entity_keys']['bundle']] = $bundle_name ?: $this->bundle;
     }
     $controller = $this->container->get('entity.manager')->getStorageController($this->entityType);
-    if (!($controller instanceof DatabaseStorageControllerNG)) {
+    if (!($controller instanceof FieldableDatabaseStorageController)) {
       foreach ($values as $property => $value) {
         if (is_array($value)) {
           $entity_values[$property] = array($langcode => $value);
diff --git a/core/modules/entity_reference/lib/Drupal/entity_reference/Plugin/field/field_type/ConfigurableEntityReferenceItem.php b/core/modules/entity_reference/lib/Drupal/entity_reference/Plugin/field/field_type/ConfigurableEntityReferenceItem.php
index ee5e79a..bcfa301 100644
--- a/core/modules/entity_reference/lib/Drupal/entity_reference/Plugin/field/field_type/ConfigurableEntityReferenceItem.php
+++ b/core/modules/entity_reference/lib/Drupal/entity_reference/Plugin/field/field_type/ConfigurableEntityReferenceItem.php
@@ -68,7 +68,7 @@ public static function schema(FieldInterface $field) {
 
     // Create a foreign key to the target entity type base type.
     $entity_manager = \Drupal::service('entity.manager');
-    if (is_subclass_of($entity_manager->getControllerClass($field['settings']['target_type'], 'storage'), 'Drupal\Core\Entity\DatabaseStorageController')) {
+    if (is_subclass_of($entity_manager->getControllerClass($field['settings']['target_type'], 'storage'), 'Drupal\Core\Entity\FieldableDatabaseStorageController')) {
       $entity_info = $entity_manager->getDefinition($field['settings']['target_type']);
 
       $base_table = $entity_info['base_table'];
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 2a50949..82fae68 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,7 +7,7 @@
 
 namespace Drupal\entity_reference\Tests;
 
-use Drupal\Core\Entity\DatabaseStorageController;
+use Drupal\Core\Entity\FieldableDatabaseStorageController;
 use Drupal\Core\Entity\Field\FieldInterface;
 use Drupal\Core\Entity\Field\FieldItemInterface;
 use Drupal\Core\Language\Language;
@@ -115,12 +115,12 @@ public function testEntityReferenceFieldSchema() {
     $foreign_key_column_name = 'target_id';
 
     // Grab the SQL schema and verify that the 'foreign keys' are present.
-    $schemas = DatabaseStorageController::_fieldSqlSchema($field);
-    $schema = $schemas[DatabaseStorageController::_fieldTableName($field)];
+    $schemas = FieldableDatabaseStorageController::_fieldSqlSchema($field);
+    $schema = $schemas[FieldableDatabaseStorageController::_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 = DatabaseStorageController::_fieldColumnName($field, $foreign_key_column_name);
+    $foreign_key_column = FieldableDatabaseStorageController::_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.');
 
@@ -130,8 +130,8 @@ public function testEntityReferenceFieldSchema() {
     entity_reference_create_instance('entity_test', 'entity_test', $field_name, 'Test vocabulary reference', 'taxonomy_vocabulary');
     $field = field_info_field('entity_test', $field_name);
 
-    $schemas = DatabaseStorageController::_fieldSqlSchema($field);
-    $schema = $schemas[DatabaseStorageController::_fieldTableName($field)];
+    $schemas = FieldableDatabaseStorageController::_fieldSqlSchema($field);
+    $schema = $schemas[FieldableDatabaseStorageController::_fieldTableName($field)];
     $this->assertFalse(isset($schema['foreign keys']), 'There is no foreign key in the schema.');
   }
 }
diff --git a/core/modules/field/field.install b/core/modules/field/field.install
index 5f70ee1..acbd5c6 100644
--- a/core/modules/field/field.install
+++ b/core/modules/field/field.install
@@ -6,7 +6,7 @@
  */
 
 use Drupal\Component\Uuid\Uuid;
-use Drupal\Core\Entity\DatabaseStorageController;
+use Drupal\Core\Entity\FieldableDatabaseStorageController;
 use Drupal\field\Entity\Field;
 
 /**
@@ -49,7 +49,7 @@ function _update_8003_field_create_field(array &$field_config) {
 
   // Create storage for the field. This requires a field entity, but cannot use
   // the regular entity_create() function here.
-  $schema = DatabaseStorageController::_fieldSqlSchema(new Field($field_config), $field_config['schema']);
+  $schema = FieldableDatabaseStorageController::_fieldSqlSchema(new Field($field_config), $field_config['schema']);
   foreach ($schema as $name => $table) {
     db_create_table($name, $table);
   }
@@ -119,8 +119,8 @@ function _update_8006_field_write_data_sql($entity_type, $bundle, $entity_id, $r
   $field_config = \Drupal::config("field.field.$entity_type.$field_name");
   $field = new Field($field_config);
 
-  $table_name = DatabaseStorageController::_fieldTableName($field);
-  $revision_name = DatabaseStorageController::_fieldRevisionTableName($field);
+  $table_name = FieldableDatabaseStorageController::_fieldTableName($field);
+  $revision_name = FieldableDatabaseStorageController::_fieldRevisionTableName($field);
 
   db_delete($table_name)
     ->condition('entity_id', $entity_id)
@@ -141,7 +141,7 @@ function _update_8006_field_write_data_sql($entity_type, $bundle, $entity_id, $r
         'langcode' => $langcode,
       );
       foreach ($item as $column => $value) {
-        $record[DatabaseStorageController::_fieldColumnName($field_name, $column)] = $value;
+        $record[FieldableDatabaseStorageController::_fieldColumnName($field_name, $column)] = $value;
       }
 
       $records[] = $record;
@@ -363,8 +363,8 @@ function field_update_8003() {
       $field = new Field($config);
       // Additionally, rename the data tables for deleted fields.
       $tables = array(
-        "field_deleted_data_{$record['id']}" => 'old_' . DatabaseStorageController::_fieldTableName($field),
-        "field_deleted_revision_{$record['id']}" => 'old_' . DatabaseStorageController::_fieldRevisionTableName($field),
+        "field_deleted_data_{$record['id']}" => 'old_' . FieldableDatabaseStorageController::_fieldTableName($field),
+        "field_deleted_revision_{$record['id']}" => 'old_' . FieldableDatabaseStorageController::_fieldRevisionTableName($field),
       );
       foreach ($tables as $table_old => $table_new) {
         if (db_table_exists($table_old)) {
@@ -512,7 +512,7 @@ function field_update_8006(&$sandbox) {
   $tables = array(
     array(
       'old_table' => 'field_data_' . $field_config['name'],
-      'new_table' => DatabaseStorageController::_fieldTableName($field),
+      'new_table' => FieldableDatabaseStorageController::_fieldTableName($field),
       'primary_key' => array(
         'entity_id',
         'deleted',
@@ -522,7 +522,7 @@ function field_update_8006(&$sandbox) {
     ),
     array(
       'old_table' => 'field_revision_' . $field_config['name'],
-      'new_table' => DatabaseStorageController::_fieldRevisionTableName($field),
+      'new_table' => FieldableDatabaseStorageController::_fieldRevisionTableName($field),
       'primary_key' => array(
         'entity_id',
         'revision_id',
diff --git a/core/modules/field/field.views.inc b/core/modules/field/field.views.inc
index 8269575..ac3d137 100644
--- a/core/modules/field/field.views.inc
+++ b/core/modules/field/field.views.inc
@@ -8,7 +8,7 @@
  */
 
 use Drupal\Component\Utility\NestedArray;
-use Drupal\Core\Entity\DatabaseStorageController;
+use Drupal\Core\Entity\FieldableDatabaseStorageController;
 use Drupal\Core\Entity\EntityStorageControllerInterface;
 use Drupal\field\FieldInterface;
 
@@ -70,7 +70,7 @@ function field_views_data_alter(&$data) {
 function _field_views_is_sql_entity_type(FieldInterface $field) {
   $entity_manager = \Drupal::entityManager();
   try {
-    if ($entity_manager->getStorageController($field->entity_type) instanceof DatabaseStorageController) {
+    if ($entity_manager->getStorageController($field->entity_type) instanceof FieldableDatabaseStorageController) {
       return TRUE;
     }
   }
@@ -146,13 +146,13 @@ function field_views_field_default_views_data(FieldInterface $field) {
   // Description of the field tables.
   $field_tables = array(
     EntityStorageControllerInterface::FIELD_LOAD_CURRENT => array(
-      'table' => DatabaseStorageController::_fieldTableName($field),
+      'table' => FieldableDatabaseStorageController::_fieldTableName($field),
       'alias' => "{$entity_type}__{$field->name}",
     ),
   );
   if ($supports_revisions) {
     $field_tables[EntityStorageControllerInterface::FIELD_LOAD_REVISION] = array(
-      'table' => DatabaseStorageController::_fieldRevisionTableName($field),
+      'table' => FieldableDatabaseStorageController::_fieldRevisionTableName($field),
       'alias' => "{$entity_type}_revision__{$field->name}",
     );
   }
@@ -184,7 +184,7 @@ function field_views_field_default_views_data(FieldInterface $field) {
   // Build the list of additional fields to add to queries.
   $add_fields = array('delta', 'langcode', 'bundle');
   foreach (array_keys($field['columns']) as $column) {
-    $add_fields[] = DatabaseStorageController::_fieldColumnName($field, $column);
+    $add_fields[] = FieldableDatabaseStorageController::_fieldColumnName($field, $column);
   }
   // Determine the label to use for the field. We don't have a label available
   // at the field level, so we just go through all instances and take the one
@@ -308,10 +308,10 @@ function field_views_field_default_views_data(FieldInterface $field) {
       else {
         $group = t('@group (historical data)', array('@group' => $group_name));
       }
-      $column_real_name = DatabaseStorageController::_fieldColumnName($field, $column);
+      $column_real_name = FieldableDatabaseStorageController::_fieldColumnName($field, $column);
 
       // Load all the fields from the table by default.
-      $field_sql_schema = DatabaseStorageController::_fieldSqlSchema($field);
+      $field_sql_schema = FieldableDatabaseStorageController::_fieldSqlSchema($field);
       $additional_fields = array_keys($field_sql_schema[$table]['fields']);
 
       $data[$table_alias][$column_real_name] = array(
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 ea74a94..78cc573 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,7 +7,7 @@
 
 namespace Drupal\field\Plugin\views\field;
 
-use Drupal\Core\Entity\DatabaseStorageController;
+use Drupal\Core\Entity\FieldableDatabaseStorageController;
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Entity\EntityStorageControllerInterface;
 use Drupal\Core\Language\Language;
@@ -289,7 +289,7 @@ public function clickSort($order) {
 
     $this->ensureMyTable();
     $field = field_info_field($this->definition['entity_type'], $this->definition['field_name']);
-    $column = DatabaseStorageController::_fieldColumnName($field, $this->options['click_sort_column']);
+    $column = FieldableDatabaseStorageController::_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;
diff --git a/core/modules/field/lib/Drupal/field/Tests/BulkDeleteTest.php b/core/modules/field/lib/Drupal/field/Tests/BulkDeleteTest.php
index 0baa951..f22b7d1 100644
--- a/core/modules/field/lib/Drupal/field/Tests/BulkDeleteTest.php
+++ b/core/modules/field/lib/Drupal/field/Tests/BulkDeleteTest.php
@@ -7,7 +7,7 @@
 
 namespace Drupal\field\Tests;
 
-use Drupal\Core\Entity\DatabaseStorageController;
+use Drupal\Core\Entity\FieldableDatabaseStorageController;
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\field\FieldInterface;
 
@@ -186,9 +186,9 @@ function testDeleteFieldInstance() {
     $this->assertEqual($instance['bundle'], $bundle, 'The deleted instance is for the correct bundle');
 
     // Check that the actual stored content did not change during delete.
-    $schema = DatabaseStorageController::_fieldSqlSchema($field);
-    $table = DatabaseStorageController::_fieldTableName($field);
-    $column = DatabaseStorageController::_fieldColumnName($field, 'value');
+    $schema = FieldableDatabaseStorageController::_fieldSqlSchema($field);
+    $table = FieldableDatabaseStorageController::_fieldTableName($field);
+    $column = FieldableDatabaseStorageController::_fieldColumnName($field, 'value');
     $result = db_select($table, 't')
       ->fields('t', array_keys($schema[$table]['fields']))
       ->execute();
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 1f60380..5da93b0 100644
--- a/core/modules/field/lib/Drupal/field/Tests/Views/ApiDataTest.php
+++ b/core/modules/field/lib/Drupal/field/Tests/Views/ApiDataTest.php
@@ -6,7 +6,7 @@
  */
 
 namespace Drupal\field\Tests\Views;
-use Drupal\Core\Entity\DatabaseStorageController;
+use Drupal\Core\Entity\FieldableDatabaseStorageController;
 
 /**
  * Test the produced views_data.
@@ -62,8 +62,8 @@ function testViewsData() {
     // Check the table and the joins of the first field.
     // Attached to node only.
     $field = $this->fields[0];
-    $current_table = DatabaseStorageController::_fieldTableName($field);
-    $revision_table = DatabaseStorageController::_fieldRevisionTableName($field);
+    $current_table = FieldableDatabaseStorageController::_fieldTableName($field);
+    $revision_table = FieldableDatabaseStorageController::_fieldRevisionTableName($field);
     $data[$current_table] = $views_data->get($current_table);
     $data[$revision_table] = $views_data->get($revision_table);
 
diff --git a/core/modules/file/file.install b/core/modules/file/file.install
index 7fb5772..c5ec889 100644
--- a/core/modules/file/file.install
+++ b/core/modules/file/file.install
@@ -5,7 +5,7 @@
  * Install, update and uninstall functions for File module.
  */
 
-use Drupal\Core\Entity\DatabaseStorageController;
+use Drupal\Core\Entity\FieldableDatabaseStorageController;
 use Drupal\field\Entity\Field;
 
 /**
@@ -271,10 +271,10 @@ function file_update_8003() {
     if (in_array($field_config->get('type'), array('file', 'image'))) {
       $field = new Field($field_config->get());
 
-      if (db_table_exists(DatabaseStorageController::_fieldTableName($field))) {
+      if (db_table_exists(FieldableDatabaseStorageController::_fieldTableName($field))) {
         $tables = array(
-          DatabaseStorageController::_fieldTableName($field),
-          DatabaseStorageController::_fieldRevisionTableName($field),
+          FieldableDatabaseStorageController::_fieldTableName($field),
+          FieldableDatabaseStorageController::_fieldRevisionTableName($field),
         );
 
         foreach ($tables as $table_name) {
diff --git a/core/modules/file/file.views.inc b/core/modules/file/file.views.inc
index 501ce7c..81f6066 100644
--- a/core/modules/file/file.views.inc
+++ b/core/modules/file/file.views.inc
@@ -7,7 +7,7 @@
  * @ingroup views_module_handlers
  */
 
-use Drupal\Core\Entity\DatabaseStorageController;
+use Drupal\Core\Entity\FieldableDatabaseStorageController;
 use Drupal\field\FieldInterface;
 
 /**
@@ -498,7 +498,7 @@ function file_field_views_data_views_data_alter(array &$data, FieldInterface $fi
     'id' => 'entity_reverse',
     'field_name' => $field['field_name'],
     'entity_type' => $field['entity_type'],
-    'field table' => DatabaseStorageController::_fieldTableName($field),
+    'field table' => FieldableDatabaseStorageController::_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/FileStorageController.php b/core/modules/file/lib/Drupal/file/FileStorageController.php
index 2f27551..9dbe289 100644
--- a/core/modules/file/lib/Drupal/file/FileStorageController.php
+++ b/core/modules/file/lib/Drupal/file/FileStorageController.php
@@ -7,12 +7,12 @@
 
 namespace Drupal\file;
 
-use Drupal\Core\Entity\DatabaseStorageControllerNG;
+use Drupal\Core\Entity\FieldableDatabaseStorageController;
 
 /**
  * File storage controller for files.
  */
-class FileStorageController extends DatabaseStorageControllerNG implements FileStorageControllerInterface {
+class FileStorageController extends FieldableDatabaseStorageController implements FileStorageControllerInterface {
 
   /**
    * {@inheritdoc}
diff --git a/core/modules/image/image.views.inc b/core/modules/image/image.views.inc
index 356f140..786559a 100644
--- a/core/modules/image/image.views.inc
+++ b/core/modules/image/image.views.inc
@@ -7,7 +7,7 @@
  * @ingroup views_module_handlers
  */
 
-use Drupal\Core\Entity\DatabaseStorageController;
+use Drupal\Core\Entity\FieldableDatabaseStorageController;
 use Drupal\field\FieldInterface;
 
 /**
@@ -52,7 +52,7 @@ function image_field_views_data_views_data_alter(array &$data, FieldInterface $f
     'id' => 'entity_reverse',
     'field_name' => $field['field_name'],
     'entity_type' => $field['entity_type'],
-    'field table' => DatabaseStorageController::_fieldTableName($field),
+    'field table' => FieldableDatabaseStorageController::_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/menu_link/lib/Drupal/menu_link/MenuLinkStorageController.php b/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkStorageController.php
index 7330147..38d6175 100644
--- a/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkStorageController.php
+++ b/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkStorageController.php
@@ -53,13 +53,11 @@ 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, FieldInfo $field_info, RouteProviderInterface $route_provider) {
-    parent::__construct($entity_type, $entity_info, $database, $field_info);
+  public function __construct($entity_type, array $entity_info, Connection $database, RouteProviderInterface $route_provider) {
+    parent::__construct($entity_type, $entity_info, $database);
 
     $this->routeProvider = $route_provider;
 
@@ -88,7 +86,6 @@ public static function createInstance(ContainerInterface $container, $entity_typ
       $entity_type,
       $entity_info,
       $container->get('database'),
-      $container->get('field.info'),
       $container->get('router.route_provider')
     );
   }
@@ -170,7 +167,6 @@ public function save(EntityInterface $entity) {
       // Unlike the save() method from DatabaseStorageController, we invoke the
       // 'presave' hook first because we want to allow modules to alter the
       // entity before all the logic from our preSave() method.
-      $this->invokeFieldMethod('preSave', $entity);
       $this->invokeHook('presave', $entity);
       $entity->preSave($this);
 
@@ -186,8 +182,6 @@ public function save(EntityInterface $entity) {
           if (!$entity->isNew()) {
             $this->resetCache(array($entity->{$this->idKey}));
             $entity->postSave($this, TRUE);
-            $this->invokeFieldMethod('update', $entity);
-            $this->saveFieldItems($entity, TRUE);
             $this->invokeHook('update', $entity);
           }
           else {
@@ -196,8 +190,6 @@ public function save(EntityInterface $entity) {
 
             $entity->enforceIsNew(FALSE);
             $entity->postSave($this, FALSE);
-            $this->invokeFieldMethod('insert', $entity);
-            $this->saveFieldItems($entity, FALSE);
             $this->invokeHook('insert', $entity);
           }
         }
diff --git a/core/modules/node/lib/Drupal/node/NodeStorageController.php b/core/modules/node/lib/Drupal/node/NodeStorageController.php
index 1360af3..f7192f1 100644
--- a/core/modules/node/lib/Drupal/node/NodeStorageController.php
+++ b/core/modules/node/lib/Drupal/node/NodeStorageController.php
@@ -7,7 +7,7 @@
 
 namespace Drupal\node;
 
-use Drupal\Core\Entity\DatabaseStorageControllerNG;
+use Drupal\Core\Entity\FieldableDatabaseStorageController;
 use Drupal\Core\Entity\EntityInterface;
 
 /**
@@ -16,7 +16,7 @@
  * This extends the Drupal\Core\Entity\DatabaseStorageController class, adding
  * required special handling for node entities.
  */
-class NodeStorageController extends DatabaseStorageControllerNG {
+class NodeStorageController extends FieldableDatabaseStorageController {
 
   /**
    * Overrides Drupal\Core\Entity\DatabaseStorageController::create().
@@ -30,7 +30,7 @@ public function create(array $values) {
   }
 
   /**
-   * Overrides Drupal\Core\Entity\DatabaseStorageControllerNG::attachLoad().
+   * Overrides Drupal\Core\Entity\DatabaseStorageController::attachLoad().
    */
   protected function attachLoad(&$queried_entities, $load_revision = FALSE) {
     $queried_entities = $this->mapFromStorageRecords($queried_entities, $load_revision);
diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/FieldSqlStorageTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/FieldSqlStorageTest.php
index 4988b49..c05f0c6 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Entity/FieldSqlStorageTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Entity/FieldSqlStorageTest.php
@@ -8,7 +8,7 @@
 namespace Drupal\system\Tests\Entity;
 
 use Drupal\Core\Database\Database;
-use Drupal\Core\Entity\DatabaseStorageController;
+use Drupal\Core\Entity\FieldableDatabaseStorageController;
 use Drupal\field\FieldException;
 use Drupal\field\Entity\Field;
 use Drupal\system\Tests\Entity\EntityUnitTestBase;
@@ -84,8 +84,8 @@ function setUp() {
     ));
     $this->instance->save();
 
-    $this->table = DatabaseStorageController::_fieldTableName($this->field);
-    $this->revision_table = DatabaseStorageController::_fieldRevisionTableName($this->field);
+    $this->table = FieldableDatabaseStorageController::_fieldTableName($this->field);
+    $this->revision_table = FieldableDatabaseStorageController::_fieldRevisionTableName($this->field);
   }
 
   /**
@@ -95,7 +95,7 @@ function testFieldLoad() {
     $entity_type = $bundle = 'entity_test_rev';
     $storage_controller = $this->container->get('entity.manager')->getStorageController($entity_type);
 
-    $columns = array('bundle', 'deleted', 'entity_id', 'revision_id', 'delta', 'langcode', DatabaseStorageController::_fieldColumnName($this->field, 'value'));
+    $columns = array('bundle', 'deleted', 'entity_id', 'revision_id', 'delta', 'langcode', FieldableDatabaseStorageController::_fieldColumnName($this->field, 'value'));
 
     // Create an entity with four revisions.
     $revision_ids = array();
@@ -352,7 +352,7 @@ function testFieldUpdateFailure() {
     }
 
     // Ensure that the field tables are still there.
-    foreach (DatabaseStorageController::_fieldSqlSchema($prior_field) as $table_name => $table_info) {
+    foreach (FieldableDatabaseStorageController::_fieldSqlSchema($prior_field) as $table_name => $table_info) {
       $this->assertTrue(db_table_exists($table_name), t('Table %table exists.', array('%table' => $table_name)));
     }
   }
@@ -376,7 +376,7 @@ function testFieldUpdateIndexesWithData() {
       'bundle' => $entity_type,
     ));
     $instance->save();
-    $tables = array(DatabaseStorageController::_fieldTableName($field), DatabaseStorageController::_fieldRevisionTableName($field));
+    $tables = array(FieldableDatabaseStorageController::_fieldTableName($field), FieldableDatabaseStorageController::_fieldRevisionTableName($field));
 
     // Verify the indexes we will create do not exist yet.
     foreach ($tables as $table) {
@@ -449,11 +449,11 @@ function testFieldSqlStorageForeignKeys() {
     $this->assertEqual($schema['foreign keys'][$foreign_key_name]['columns'][$foreign_key_name], 'id', 'Foreign key column name modified after update');
 
     // Verify the SQL schema.
-    $schemas = DatabaseStorageController::_fieldSqlSchema($field);
-    $schema = $schemas[DatabaseStorageController::_fieldTableName($field)];
+    $schemas = FieldableDatabaseStorageController::_fieldSqlSchema($field);
+    $schema = $schemas[FieldableDatabaseStorageController::_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 = DatabaseStorageController::_fieldColumnName($field, $foreign_key_name);
+    $foreign_key_column = FieldableDatabaseStorageController::_fieldColumnName($field, $foreign_key_name);
     $this->assertEqual($foreign_key['table'], $foreign_key_name, 'Foreign key table name preserved in the schema');
     $this->assertEqual($foreign_key['columns'][$foreign_key_column], 'id', 'Foreign key column name preserved in the schema');
   }
@@ -475,9 +475,9 @@ public function testTableNames() {
       'type' => 'test_field',
     ));
     $expected = 'short_entity_type__short_field_name';
-    $this->assertEqual(DatabaseStorageController::_fieldTableName($field), $expected);
+    $this->assertEqual(FieldableDatabaseStorageController::_fieldTableName($field), $expected);
     $expected = 'short_entity_type_revision__short_field_name';
-    $this->assertEqual(DatabaseStorageController::_fieldRevisionTableName($field), $expected);
+    $this->assertEqual(FieldableDatabaseStorageController::_fieldRevisionTableName($field), $expected);
 
     // Short entity type, long field name
     $entity_type = 'short_entity_type';
@@ -488,9 +488,9 @@ public function testTableNames() {
       'type' => 'test_field',
     ));
     $expected = 'short_entity_type__' . substr(hash('sha256', $field->uuid), 0, 10);
-    $this->assertEqual(DatabaseStorageController::_fieldTableName($field), $expected);
+    $this->assertEqual(FieldableDatabaseStorageController::_fieldTableName($field), $expected);
     $expected = 'short_entity_type_r__' . substr(hash('sha256', $field->uuid), 0, 10);
-    $this->assertEqual(DatabaseStorageController::_fieldRevisionTableName($field), $expected);
+    $this->assertEqual(FieldableDatabaseStorageController::_fieldRevisionTableName($field), $expected);
 
     // Long entity type, short field name
     $entity_type = 'long_entity_type_abcdefghijklmnopqrstuvwxyz';
@@ -501,9 +501,9 @@ public function testTableNames() {
       'type' => 'test_field',
     ));
     $expected = 'long_entity_type_abcdefghijklmnopq__' . substr(hash('sha256', $field->uuid), 0, 10);
-    $this->assertEqual(DatabaseStorageController::_fieldTableName($field), $expected);
+    $this->assertEqual(FieldableDatabaseStorageController::_fieldTableName($field), $expected);
     $expected = 'long_entity_type_abcdefghijklmnopq_r__' . substr(hash('sha256', $field->uuid), 0, 10);
-    $this->assertEqual(DatabaseStorageController::_fieldRevisionTableName($field), $expected);
+    $this->assertEqual(FieldableDatabaseStorageController::_fieldRevisionTableName($field), $expected);
 
     // Long entity type and field name.
     $entity_type = 'long_entity_type_abcdefghijklmnopqrstuvwxyz';
@@ -514,17 +514,17 @@ public function testTableNames() {
       'type' => 'test_field',
     ));
     $expected = 'long_entity_type_abcdefghijklmnopq__' . substr(hash('sha256', $field->uuid), 0, 10);
-    $this->assertEqual(DatabaseStorageController::_fieldTableName($field), $expected);
+    $this->assertEqual(FieldableDatabaseStorageController::_fieldTableName($field), $expected);
     $expected = 'long_entity_type_abcdefghijklmnopq_r__' . substr(hash('sha256', $field->uuid), 0, 10);
-    $this->assertEqual(DatabaseStorageController::_fieldRevisionTableName($field), $expected);
+    $this->assertEqual(FieldableDatabaseStorageController::_fieldRevisionTableName($field), $expected);
     // Try creating a second field and check there are no clashes.
     $field2 = entity_create('field_entity', array(
       'entity_type' => $entity_type,
       'name' => $field_name . '2',
       'type' => 'test_field',
     ));
-    $this->assertNotEqual(DatabaseStorageController::_fieldTableName($field), DatabaseStorageController::_fieldTableName($field2));
-    $this->assertNotEqual(DatabaseStorageController::_fieldRevisionTableName($field), DatabaseStorageController::_fieldRevisionTableName($field2));
+    $this->assertNotEqual(FieldableDatabaseStorageController::_fieldTableName($field), FieldableDatabaseStorageController::_fieldTableName($field2));
+    $this->assertNotEqual(FieldableDatabaseStorageController::_fieldRevisionTableName($field), FieldableDatabaseStorageController::_fieldRevisionTableName($field2));
 
     // Deleted field.
     $field = entity_create('field_entity', array(
@@ -534,9 +534,9 @@ public function testTableNames() {
       'deleted' => TRUE,
     ));
     $expected = 'field_deleted_data_' . substr(hash('sha256', $field->uuid), 0, 10);
-    $this->assertEqual(DatabaseStorageController::_fieldTableName($field), $expected);
+    $this->assertEqual(FieldableDatabaseStorageController::_fieldTableName($field), $expected);
     $expected = 'field_deleted_revision_' . substr(hash('sha256', $field->uuid), 0, 10);
-    $this->assertEqual(DatabaseStorageController::_fieldRevisionTableName($field), $expected);
+    $this->assertEqual(FieldableDatabaseStorageController::_fieldRevisionTableName($field), $expected);
   }
 
 }
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 d615512..4c3757a 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Upgrade/FieldUpgradePathTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Upgrade/FieldUpgradePathTest.php
@@ -7,7 +7,7 @@
 
 namespace Drupal\system\Tests\Upgrade;
 
-use Drupal\Core\Entity\DatabaseStorageController;
+use Drupal\Core\Entity\FieldableDatabaseStorageController;
 use Drupal\field\Entity\Field;
 
 /**
@@ -278,7 +278,7 @@ function testFieldUpgradeToConfig() {
 
     // Check that pre-existing deleted field table is renamed correctly.
     $field_entity = new Field($deleted_field);
-    $table_name = DatabaseStorageController::_fieldTableName($field_entity);
+    $table_name = FieldableDatabaseStorageController::_fieldTableName($field_entity);
     $this->assertEqual("field_deleted_data_" . substr(hash('sha256', $deleted_field['uuid']), 0, 10), $table_name);
     $this->assertTrue(db_table_exists($table_name));
 
diff --git a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestStorageController.php b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestStorageController.php
index bb8d390..a348fc6 100644
--- a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestStorageController.php
+++ b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestStorageController.php
@@ -7,7 +7,7 @@
 
 namespace Drupal\entity_test;
 
-use Drupal\Core\Entity\DatabaseStorageControllerNG;
+use Drupal\Core\Entity\FieldableDatabaseStorageController;
 
 /**
  * Defines the controller class for the test entity.
@@ -15,7 +15,7 @@
  * This extends the Drupal\Core\Entity\DatabaseStorageController class, adding
  * required special handling for test entities.
  */
-class EntityTestStorageController extends DatabaseStorageControllerNG {
+class EntityTestStorageController extends FieldableDatabaseStorageController {
 
   /**
    * {@inheritdoc}
diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/TermStorageController.php b/core/modules/taxonomy/lib/Drupal/taxonomy/TermStorageController.php
index f77b1b5..1a47334 100644
--- a/core/modules/taxonomy/lib/Drupal/taxonomy/TermStorageController.php
+++ b/core/modules/taxonomy/lib/Drupal/taxonomy/TermStorageController.php
@@ -9,12 +9,12 @@
 
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Entity\Query\QueryInterface;
-use Drupal\Core\Entity\DatabaseStorageControllerNG;
+use Drupal\Core\Entity\FieldableDatabaseStorageController;
 
 /**
  * Defines a Controller class for taxonomy terms.
  */
-class TermStorageController extends DatabaseStorageControllerNG implements TermStorageControllerInterface {
+class TermStorageController extends FieldableDatabaseStorageController implements TermStorageControllerInterface {
 
   /**
    * Overrides Drupal\Core\Entity\DatabaseStorageController::create().
diff --git a/core/modules/taxonomy/taxonomy.install b/core/modules/taxonomy/taxonomy.install
index 775527d..7e03b90 100644
--- a/core/modules/taxonomy/taxonomy.install
+++ b/core/modules/taxonomy/taxonomy.install
@@ -6,7 +6,7 @@
  */
 
 use Drupal\Component\Uuid\Uuid;
-use Drupal\Core\Entity\DatabaseStorageController;
+use Drupal\Core\Entity\FieldableDatabaseStorageController;
 use Drupal\field\Entity\Field;
 
 /**
@@ -354,10 +354,10 @@ function taxonomy_update_8007() {
     if ($field_config->get('type') == 'taxonomy_term_reference') {
       $field = new Field($field_config->get());
 
-      if (db_table_exists(DatabaseStorageController::_fieldTableName($field))) {
+      if (db_table_exists(FieldableDatabaseStorageController::_fieldTableName($field))) {
         $tables = array(
-          DatabaseStorageController::_fieldTableName($field),
-          DatabaseStorageController::_fieldRevisionTableName($field),
+          FieldableDatabaseStorageController::_fieldTableName($field),
+          FieldableDatabaseStorageController::_fieldRevisionTableName($field),
         );
 
         foreach ($tables as $table_name) {
diff --git a/core/modules/taxonomy/taxonomy.module b/core/modules/taxonomy/taxonomy.module
index 81537b6..a5aa1cd 100644
--- a/core/modules/taxonomy/taxonomy.module
+++ b/core/modules/taxonomy/taxonomy.module
@@ -5,7 +5,7 @@
  * Enables the organization of content into categories.
  */
 
-use Drupal\Core\Entity\DatabaseStorageController;
+use Drupal\Core\Entity\FieldableDatabaseStorageController;
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Entity\Field\FieldDefinitionInterface;
 use Drupal\node\Entity\Node;
@@ -1099,7 +1099,7 @@ 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.
-  if (!\Drupal::config('taxonomy.settings')->get('maintain_index_table') || !(\Drupal::entityManager()->getStorageController('node') instanceof DatabaseStorageController)) {
+  if (!\Drupal::config('taxonomy.settings')->get('maintain_index_table') || !(\Drupal::entityManager()->getStorageController('node') instanceof FieldableDatabaseStorageController)) {
     return;
   }
 
diff --git a/core/modules/taxonomy/taxonomy.views.inc b/core/modules/taxonomy/taxonomy.views.inc
index 4e9f27c..727d2a6 100644
--- a/core/modules/taxonomy/taxonomy.views.inc
+++ b/core/modules/taxonomy/taxonomy.views.inc
@@ -7,7 +7,7 @@
  * @ingroup views_module_handlers
  */
 
-use Drupal\Core\Entity\DatabaseStorageController;
+use Drupal\Core\Entity\FieldableDatabaseStorageController;
 use Drupal\field\FieldInterface;
 
 /**
@@ -448,7 +448,7 @@ function taxonomy_field_views_data_views_data_alter(array &$data, FieldInterface
     'id' => 'entity_reverse',
     'field_name' => $field['field_name'],
     'entity_type' => $field['entity_type'],
-    'field table' => DatabaseStorageController::_fieldTableName($field),
+    'field table' => FieldableDatabaseStorageController::_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/user/lib/Drupal/user/UserStorageController.php b/core/modules/user/lib/Drupal/user/UserStorageController.php
index 9cbcf0e..cc6b152 100644
--- a/core/modules/user/lib/Drupal/user/UserStorageController.php
+++ b/core/modules/user/lib/Drupal/user/UserStorageController.php
@@ -13,7 +13,7 @@
 use Drupal\field\FieldInfo;
 use Drupal\user\UserDataInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
-use Drupal\Core\Entity\DatabaseStorageControllerNG;
+use Drupal\Core\Entity\FieldableDatabaseStorageController;
 
 /**
  * Controller class for users.
@@ -21,7 +21,7 @@
  * This extends the Drupal\Core\Entity\DatabaseStorageController class, adding
  * required special handling for user objects.
  */
-class UserStorageController extends DatabaseStorageControllerNG implements UserStorageControllerInterface {
+class UserStorageController extends FieldableDatabaseStorageController implements UserStorageControllerInterface {
 
   /**
    * Provides the password hashing service object.
diff --git a/core/modules/views/lib/Drupal/views/Tests/QueryGroupByTest.php b/core/modules/views/lib/Drupal/views/Tests/QueryGroupByTest.php
index edb6737..7c09bbf 100644
--- a/core/modules/views/lib/Drupal/views/Tests/QueryGroupByTest.php
+++ b/core/modules/views/lib/Drupal/views/Tests/QueryGroupByTest.php
@@ -29,7 +29,7 @@ class QueryGroupByTest extends ViewUnitTestBase {
   /**
    * The storage controller for the test entity type.
    *
-   * @var \Drupal\Core\Entity\DatabaseStorageController
+   * @var \Drupal\Core\Entity\FieldableDatabaseStorageController
    */
   public $storageController;
 
