diff --git a/core/includes/schema.inc b/core/includes/schema.inc
index 47e7836..5773d71 100644
--- a/core/includes/schema.inc
+++ b/core/includes/schema.inc
@@ -370,13 +370,15 @@ function drupal_schema_fields_sql($table, $prefix = NULL) {
  *   If the record insert or update failed, returns FALSE. If it succeeded,
  *   returns SAVED_NEW or SAVED_UPDATED, depending on the operation performed.
  */
-function drupal_write_record($table, &$record, $primary_keys = array()) {
+function drupal_write_record($table, &$record, $primary_keys = array(), $schema = NULL) {
   // Standardize $primary_keys to an array.
   if (is_string($primary_keys)) {
     $primary_keys = array($primary_keys);
   }
 
-  $schema = drupal_get_schema($table);
+  if (!isset($schema)) {
+    $schema = drupal_get_schema($table);
+  }
   if (empty($schema)) {
     return FALSE;
   }
diff --git a/core/lib/Drupal/Core/Entity/FieldableDatabaseStorageController.php b/core/lib/Drupal/Core/Entity/FieldableDatabaseStorageController.php
index 222145f..43eb437 100644
--- a/core/lib/Drupal/Core/Entity/FieldableDatabaseStorageController.php
+++ b/core/lib/Drupal/Core/Entity/FieldableDatabaseStorageController.php
@@ -40,6 +40,13 @@ class FieldableDatabaseStorageController extends FieldableEntityStorageControlle
   protected $revisionKey = FALSE;
 
   /**
+   * The base table of the entity, if the entity has storage.
+   *
+   * @var string
+   */
+  protected $baseTable;
+
+  /**
    * The table that stores revisions, if the entity supports revisions.
    *
    * @var string
@@ -68,6 +75,13 @@ class FieldableDatabaseStorageController extends FieldableEntityStorageControlle
   protected $cache;
 
   /**
+   * The computed schema array of this entity type.
+   *
+   * @var array
+   */
+  protected $schema;
+
+  /**
    * Active database connection.
    *
    * @var \Drupal\Core\Database\Connection
@@ -116,6 +130,11 @@ public function __construct(EntityTypeInterface $entity_type, Connection $databa
     // Check if the entity type supports UUIDs.
     $this->uuidKey = $this->entityType->getKey('uuid');
 
+    // Some entity types are not stored in the database at all.
+    if ($base_table = $this->entityType->getBaseTable()) {
+      $this->baseTable = $base_table;
+    }
+
     // Check if the entity type supports revisions.
     if ($this->entityType->hasKey('revision')) {
       $this->revisionKey = $this->entityType->getKey('revision');
@@ -123,12 +142,14 @@ public function __construct(EntityTypeInterface $entity_type, Connection $databa
     }
 
     // Check if the entity type has a dedicated table for fields.
+    // @todo Replace this with a check for the 'language' entity key when
+    //   https://drupal.org/node/2143729 has landed.
     if ($data_table = $this->entityType->getDataTable()) {
       $this->dataTable = $data_table;
       // Entity types having both revision and translation support should always
       // define a revision data table.
-      if ($this->revisionTable && $revision_data_table = $this->entityType->getRevisionDataTable()) {
-        $this->revisionDataTable = $revision_data_table;
+      if ($this->revisionTable) {
+        $this->revisionDataTable = $this->entityType->getRevisionDataTable();
       }
     }
   }
@@ -139,6 +160,11 @@ public function __construct(EntityTypeInterface $entity_type, Connection $databa
   public function loadMultiple(array $ids = NULL) {
     $entities = array();
 
+    // If the schema has not been initialized yet, no entities exist.
+    if (!$this->schemaExists()) {
+      return $entities;
+    }
+
     // Create a new variable which is either a prepared version of the $ids
     // array for later comparison with the entity cache, or FALSE if no $ids
     // were passed. The $ids array is reduced as items are loaded from cache,
@@ -319,6 +345,10 @@ protected function attachPropertyData(array &$entities) {
    * Implements \Drupal\Core\Entity\EntityStorageControllerInterface::loadRevision().
    */
   public function loadRevision($revision_id) {
+    if (!$this->schemaExists()) {
+      return FALSE;
+    }
+
     // Build and execute the query.
     $query_result = $this->buildQuery(array(), $revision_id)->execute();
     $queried_entities = $query_result->fetchAllAssoc($this->idKey);
@@ -469,7 +499,7 @@ protected function postLoad(array &$queried_entities) {
    * Implements \Drupal\Core\Entity\EntityStorageControllerInterface::delete().
    */
   public function delete(array $entities) {
-    if (!$entities) {
+    if (!$entities || $this->schemaExists()) {
       // If no IDs or invalid IDs were passed, do nothing.
       return;
     }
@@ -534,6 +564,8 @@ public function delete(array $entities) {
   public function save(EntityInterface $entity) {
     $transaction = $this->database->startTransaction();
     try {
+      $this->ensureSchema();
+
       // Sync the changes made in the fields array to the internal values array.
       $entity->updateOriginalValues();
 
@@ -551,7 +583,7 @@ public function save(EntityInterface $entity) {
 
       if (!$entity->isNew()) {
         if ($entity->isDefaultRevision()) {
-          $return = drupal_write_record($this->entityType->getBaseTable(), $record, $this->idKey);
+          $return = drupal_write_record($this->baseTable, $record, $this->idKey, $this->getSchema('base_table'));
         }
         else {
           // @todo, should a different value be returned when saving an entity
@@ -581,7 +613,7 @@ public function save(EntityInterface $entity) {
         // Ensure the entity is still seen as new after assigning it an id,
         // while storing its data.
         $entity->enforceIsNew();
-        $return = drupal_write_record($this->entityType->getBaseTable(), $record);
+        $return = drupal_write_record($this->baseTable, $record, array(), $this->getSchema('base_table'));
         $entity->{$this->idKey}->value = (string) $record->{$this->idKey};
         if ($this->revisionTable) {
           $entity->setNewRevision();
@@ -669,11 +701,16 @@ protected function mapToStorageRecord(EntityInterface $entity, $table_key = 'bas
     $record = new \stdClass();
     $values = array();
     $definitions = $entity->getFieldDefinitions();
-    $schema = drupal_get_schema($this->entityType->get($table_key));
+    $schema = $this->getSchema($table_key);
+    // Backwards-compatibility layer for entity types that declare their schema
+    // in hook_schema() manually.
+    if (!$schema) {
+      $schema = drupal_get_schema($this->entityType->get($table_key));
+    }
     $is_new = $entity->isNew();
 
     $multi_column_fields = array();
-    foreach (drupal_schema_fields_sql($this->entityType->get($table_key)) as $name) {
+    foreach (array_keys($schema['fields']) as $name) {
       // Check for fields which store data in multiple columns and process them
       // separately.
       if ($field = strstr($name, '__', TRUE)) {
@@ -746,7 +783,7 @@ protected function saveRevision(EntityInterface $entity) {
     $entity->preSaveRevision($this, $record);
 
     if ($entity->isNewRevision()) {
-      drupal_write_record($this->revisionTable, $record);
+      drupal_write_record($this->revisionTable, $record, array(), $this->getSchema('revision_table'));
       if ($entity->isDefaultRevision()) {
         $this->database->update($this->entityType->getBaseTable())
           ->fields(array($this->revisionKey => $record->{$this->revisionKey}))
@@ -755,7 +792,7 @@ protected function saveRevision(EntityInterface $entity) {
       }
     }
     else {
-      drupal_write_record($this->revisionTable, $record, $this->revisionKey);
+      drupal_write_record($this->revisionTable, $record, $this->revisionKey, $this->getSchema('revision_table'));
     }
 
     // Make sure to update the new revision key for the entity.
@@ -1455,4 +1492,286 @@ static public function _fieldColumnName(FieldConfigInterface $field, $column) {
     return in_array($column, FieldConfig::getReservedColumns()) ? $column : $field->getName() . '_' . $column;
   }
 
+  /**
+   * Gets the schema for this entity type.
+   *
+   * @param string $table_key
+   *   (optional) The entity key identifying the target table to return the
+   *   schema for. If omitted, returns the schema for all table types.
+   *
+   * @return array|null
+   *   Returns the schema definitions for the entity type's tables. If the
+   *   entity type does not have a schema, returns NULL.
+   *
+   * @throws \LogicException
+   */
+  public function getSchema($table_key = NULL) {
+    $passed_table_key = $table_key;
+
+    $tables = array_filter(array(
+      'base_table' => $this->baseTable,
+      'revision_table' => $this->revisionTable,
+      'data_table' => $this->dataTable,
+      'revision_data_table' => $this->revisionDataTable,
+    ));
+
+    // If this entity type does not support storage, no schema information can
+    // be collected.
+    if (empty($tables)) {
+      $this->schema = NULL;
+    }
+
+    if (!isset($this->schema)) {
+      $entity_type_id = $this->entityTypeId;
+      $entity_keys = array_filter(array(
+        'id' => $this->idKey,
+        'revision' => $this->revisionKey,
+        'bundle' => $this->bundleKey,
+        'uuid' => $this->uuidKey,
+      ));
+
+      // Prepare a mapping of which fields should be stored on which table. This
+      // information depends on which table types are provided.
+      if (!isset($tables['data_table']) && !isset($tables['revision_table'])) {
+        // In the simplest case all fields are stored in the base table.
+        $field_table_mapping = array('base_table' => array_values($entity_keys));
+        $other_fields_tables = array('base_table');
+      }
+      elseif (!isset($tables['data_table']) && isset($tables['revision_table'])) {
+        // For non-translatable, revisionable entities the entity key fields
+        // except for ID and revision ID are only stored in the base table. The ID
+        // is stored in both the base table and the revision table and the
+        // revision ID is only stored in the revision table. Additionally, the
+        // default revision ID of an entity is tracked as the revision ID field in
+        // the base table.
+        // Other fields are stored in the in the revision table and other fields
+        // of the default revision are stored in the the base table.
+        $field_table_mapping = array(
+          'base_table' => array_values($entity_keys),
+          'revision_table' => array($entity_keys['id'], $entity_keys['revision']),
+        );
+        $other_fields_tables = array('base_table', 'revision_table');
+      }
+      elseif (isset($tables['data_table']) && !isset($tables['revision_table'])) {
+        // @todo Remove this when https://drupal.org/node/2143729 has landed
+        $entity_keys['langcode'] = 'langcode';
+
+        // For translatable, non-revisionable entities the entity key fields
+        // except for ID and language code are only stored in the base table. All
+        // other fields are only stored in the data table. The ID is stored in
+        // both the base table and the data table and the language code is only
+        // stored in the data table. Additionally, whether or not a language
+        // variant belongs to the default language code of an entity is tracked in
+        // the data table as the default language code field and the respective
+        // default language code is stored as the language code field in the base
+        // table.
+        $field_table_mapping = array(
+          'base_table' => array_values($entity_keys),
+          'data_table' => array($entity_keys['id'], 'langcode', 'default_langcode'),
+        );
+        $other_fields_tables = array('data_table');
+      }
+      else {
+        // @todo Remove this when https://drupal.org/node/2143729 has landed
+        $entity_keys['langcode'] = 'langcode';
+
+        // For translatable, revisionable entities the entity key fields except
+        // for ID, language code and revision ID are only stored on the base
+        // table. The ID is stored on the base table, the data table, the revision
+        // table, and the revision data table. The language code is stored both on
+        // the data table and the revision data table. Additionally, whether or
+        // not a language variant belongs to the default language code of an
+        // entity is tracked in the data table as the default language code field
+        // and the respective default language code is stored as the language code
+        // field in the base table. Similarly, whether or not a language variant
+        // belongs to the default language code of an entity revision is tracked
+        // in the revision data table as the default language code field and the
+        // respective default language code is stored as the language code field
+        // in the revision table. Furthermore, the revision ID is stored both in
+        // the revision table and the revision data table. Additionally, the
+        // default revision ID of an entity is tracked as the revision ID field in
+        // both the base table and the data table. Other fields are stored in the
+        // revision data table and other fields of the default revision are stored
+        // in the data table.
+        $field_table_mapping = array(
+          'base_table' => array_values($entity_keys),
+          'revision_table' => array($entity_keys['id'], $entity_keys['revision'], 'langcode'),
+          'data_table' => array($entity_keys['id'], $entity_keys['revision'], 'langcode', 'default_langcode'),
+          'revision_data_table' => array($entity_keys['id'], $entity_keys['revision'], 'langcode', 'default_langcode'),
+        );
+        $other_fields_tables = array('data_table', 'revision_data_table');
+      }
+
+      // Add primary keys and common foreign keys to the tables.
+      $this->schema[$tables['base_table']]['primary key'] = array($entity_keys['id']);
+      $this->schema[$tables['base_table']]['foreign keys'] = array();
+      if (isset($tables['data_table'])) {
+        $this->schema[$tables['data_table']]['primary key'] = array($entity_keys['id'], 'langcode');
+        $this->schema[$tables['data_table']]['foreign keys'][$entity_keys['id']] = array(
+          'table' => $tables['base_table'],
+          'columns' => array($entity_keys['id'] => $entity_keys['id']),
+        );
+      }
+      if (isset($tables['revision_table'])) {
+        $this->schema[$tables['revision_table']]['primary key'] = array($entity_keys['revision']);
+        $this->schema[$tables['revision_table']]['foreign keys'][$entity_keys['id']] = array(
+          'table' => $tables['base_table'],
+          'columns' => array($entity_keys['id'] => $entity_keys['id']),
+        );
+      }
+      if (isset($tables['revision_data_table'])) {
+        $this->schema[$tables['revision_data_table']]['primary key'] = array($entity_keys['revision'], 'langcode');
+        $this->schema[$tables['revision_data_table']]['foreign keys'][$entity_keys['id']] = array(
+          'table' => $tables['base_table'],
+          'columns' => array($entity_keys['id'] => $entity_keys['id']),
+        );
+        $this->schema[$tables['revision_data_table']]['foreign keys'][$entity_keys['revision']] = array(
+          'table' => $tables['revision_table'],
+          'columns' => array($entity_keys['revision'] => $entity_keys['revision']),
+        );
+      }
+
+      $class = $this->entityClass;
+      // Invoke ContentEntityInterface::baseFieldDefinitions() directly. Avoid
+      // info or alter hooks.
+      foreach($class::baseFieldDefinitions($entity_type_id) as $field_name => $field_definition) {
+        /** @var \Drupal\Core\Field\FieldDefinitionInterface $field_definition */
+
+        $field_schema = $field_definition->getSchema();
+        $field_schema['description'] = $field_definition->getDescription();
+
+        $single_column_field = count($field_schema['columns']) == 1;
+        $main_property_name = $field_definition->getMainPropertyName();
+
+        if (in_array($field_name, $entity_keys)) {
+          foreach ($field_table_mapping as $table_key => $field_names) {
+            if (in_array($field_name, $field_names)) {
+              if (!$single_column_field) {
+                throw new \LogicException("The $field_name field of the $entity_type_id entity type has multiple columns.");
+              }
+              $this->schema[$tables[$table_key]]['fields'][$field_name] = $field_schema['columns'][$main_property_name];
+              $this->schema[$tables[$table_key]]['fields'][$field_name]['description'] = $field_definition->getDescription();
+
+              if (!empty($field_schema['unique keys'])) {
+                $this->schema[$tables[$table_key]]['unique keys'][$field_name] = array($field_name);
+              }
+              if (!empty($field_schema['indexes'])) {
+                // @todo Support indexes specified as an array of column name and
+                //   length.
+                $this->schema[$tables[$table_key]]['indexes'][$field_name] = array($field_name);
+              }
+              if (!empty($field_schema['foreign keys'])) {
+                $this->schema[$tables[$table_key]]['foreign keys'] += $field_schema['foreign keys'];
+              }
+            }
+          }
+        }
+        else {
+          foreach ($other_fields_tables as $table_key) {
+            if ($single_column_field) {
+              $this->schema[$tables[$table_key]]['fields'][$field_name] = $field_schema['columns'][$main_property_name];
+              $this->schema[$tables[$table_key]]['fields'][$field_name]['description'] = $field_definition->getDescription();
+
+              if (!empty($field_schema['unique keys'])) {
+                $this->schema[$tables[$table_key]]['unique keys'][$field_name] = array($field_name);
+              }
+              if (!empty($field_schema['indexes'])) {
+                // @todo Support indexes specified as an array of column name and
+                //   length.
+                $this->schema[$tables[$table_key]]['indexes'][$field_name] = array($field_name);
+              }
+              if (!empty($field_schema['foreign keys'])) {
+                $this->schema[$tables[$table_key]]['foreign keys'] += $field_schema['foreign keys'];
+              }
+            }
+            else {
+              foreach ($field_schema['columns'] as $column_name => $column_schema) {
+                $this->schema[$tables[$table_key]]['fields'][$field_name . '__' . $column_name] = $column_schema;
+              }
+
+              // @todo Unique keys, indexes and foreign keys.
+            }
+          }
+        }
+      }
+
+      // Change the ID field in the base table to 'serial' if it is 'int'.
+      if ($this->schema[$tables['base_table']]['fields'][$entity_keys['id']]['type'] == 'int') {
+        $this->schema[$tables['base_table']]['fields'][$entity_keys['id']]['type'] = 'serial';
+        unset($this->schema[$tables['base_table']]['fields'][$entity_keys['id']]['default']);
+      }
+      // Change the revision ID field in the revision table 'serial' if it is
+      // 'int'.
+      if (isset($tables['revision_table']) && $this->schema[$tables['revision_table']]['fields'][$entity_keys['revision']]['type'] == 'int') {
+        $this->schema[$tables['revision_table']]['fields'][$entity_keys['revision']]['type'] = 'serial';
+        unset($this->schema[$tables['revision_table']]['fields'][$entity_keys['revision']]['default']);
+      }
+
+      // Add table descriptions.
+      foreach ($tables as $table_key => $table) {
+        $this->schema[$table]['description'] = "The $table_key table for $entity_type_id entities.";
+      }
+    }
+
+    if (isset($passed_table_key)) {
+      if (isset($this->schema[$tables[$passed_table_key]])) {
+        return $this->schema[$tables[$passed_table_key]];
+      }
+      return;
+    }
+
+    return $this->schema;
+  }
+
+  /**
+   * Checks whether the entity tables exist in the database.
+   *
+   * @return bool
+   *   Whether or not the schema tables exist in the database.
+   */
+  protected function schemaExists() {
+    if ($this->baseTable) {
+      return $this->database->schema()->tableExists($this->baseTable);
+    }
+    // Return FALSE for entities without any storage.
+    return FALSE;
+  }
+
+  /**
+   * Ensures the entity tables exist in the database.
+   *
+   * If the entity tables do not exist, they are created according to the schema
+   * definitions computed from the entity type's fields.
+   *
+   * @see \Drupal\Core\Entity\FieldableDatabaseStorageController::getSchema()
+   *
+   * @todo Make this protected.
+   */
+  public function ensureSchema() {
+    if (!$this->schemaExists() && ($schema = $this->getSchema())) {
+      foreach ($schema as $table_name => $table_schema) {
+        $this->database->schema()->createTable($table_name, $table_schema);
+      }
+    }
+  }
+
+  /**
+   * Deletes the entity tables from the database.
+   *
+   * @todo Make this protected.
+   */
+  public function deleteSchema() {
+    if ($this->schemaExists()) {
+      $tables = array_filter(array(
+        $this->baseTable,
+        $this->revisionTable,
+        $this->dataTable,
+        $this->revisionDataTable,
+      ));
+      foreach ($tables as $table_name) {
+        $this->database->schema()->dropTable($table_name);
+      }
+    }
+  }
+
 }
diff --git a/core/lib/Drupal/Core/Entity/Query/Sql/Query.php b/core/lib/Drupal/Core/Entity/Query/Sql/Query.php
index 407cef5..62fd9a6 100644
--- a/core/lib/Drupal/Core/Entity/Query/Sql/Query.php
+++ b/core/lib/Drupal/Core/Entity/Query/Sql/Query.php
@@ -11,6 +11,7 @@
 use Drupal\Core\Database\Query\SelectInterface;
 use Drupal\Core\Entity\EntityManagerInterface;
 use Drupal\Core\Entity\EntityTypeInterface;
+use Drupal\Core\Entity\FieldableDatabaseStorageController;
 use Drupal\Core\Entity\Query\QueryBase;
 use Drupal\Core\Entity\Query\QueryException;
 use Drupal\Core\Entity\Query\QueryInterface;
@@ -53,13 +54,6 @@ class Query extends QueryBase implements QueryInterface {
   protected $connection;
 
   /**
-   * Stores the entity manager used by the query.
-   *
-   * @var \Drupal\Core\Entity\EntityManagerInterface
-   */
-  protected $entityManager;
-
-  /**
    * Constructs a query object.
    *
    * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
@@ -107,6 +101,12 @@ protected function prepare() {
     if ($this->entityType->getDataTable()) {
       $simple_query = FALSE;
     }
+
+    $storage_controller = \Drupal::entityManager()->getStorageController($this->entityTypeId);
+    if ($storage_controller instanceof FieldableDatabaseStorageController) {
+      $storage_controller->ensureSchema();
+    }
+
     $this->sqlQuery = $this->connection->select($base_table, 'base_table', array('conjunction' => $this->conjunction));
     $this->sqlQuery->addMetaData('entity_type', $this->entityTypeId);
     $id_field = $this->entityType->getKey('id');
diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/EntityReferenceItem.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/EntityReferenceItem.php
index 58a5961..90a2711 100644
--- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/EntityReferenceItem.php
+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/EntityReferenceItem.php
@@ -89,6 +89,7 @@ public static function schema(FieldDefinitionInterface $field_definition) {
           'type' => 'int',
           'unsigned' => TRUE,
           'not null' => TRUE,
+          'default' => 0,
         ),
       );
     }
diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/IntegerItem.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/IntegerItem.php
index 0a7a8cf..07c9a81 100644
--- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/IntegerItem.php
+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/IntegerItem.php
@@ -42,6 +42,7 @@ public static function schema(FieldDefinitionInterface $field_definition) {
         'value' => array(
           'type' => 'int',
           'not null' => TRUE,
+          'default' => 0,
         ),
       ),
     );
diff --git a/core/modules/system/tests/modules/entity_test/entity_test.install b/core/modules/system/tests/modules/entity_test/entity_test.install
index 3df5396..eb46f54 100644
--- a/core/modules/system/tests/modules/entity_test/entity_test.install
+++ b/core/modules/system/tests/modules/entity_test/entity_test.install
@@ -9,433 +9,57 @@
  * Implements hook_install().
  */
 function entity_test_install() {
-  $entity_types = array(
+  $entity_manager = \Drupal::entityManager();
+
+  $entity_type_ids = array(
     'entity_test',
     'entity_test_rev',
     'entity_test_mul',
     'entity_test_mulrev',
   );
-  foreach ($entity_types as $entity_type) {
+  foreach ($entity_type_ids as $entity_type_id) {
+    $storage_controller = $entity_manager->getStorageController($entity_type_id);
+
+    // Install schema.
+    $storage_controller->ensureSchema();
+
     // Auto-create fields for testing.
-    entity_create('field_config', array(
+    $storage_controller->create(array(
       'name' => 'field_test_text',
-      'entity_type' => $entity_type,
+      'entity_type' => $entity_type_id,
       'type' => 'text',
       'cardinality' => 1,
       'translatable' => FALSE,
     ))->save();
-    entity_create('field_instance_config', array(
-      'entity_type' => $entity_type,
+    $storage_controller->create(array(
+      'entity_type' => $entity_type_id,
       'field_name' => 'field_test_text',
-      'bundle' => $entity_type,
+      'bundle' => $entity_type_id,
       'label' => 'Test text-field',
     ))->save();
 
-    entity_get_form_display($entity_type, $entity_type, 'default')
+    entity_get_form_display($entity_type_id, $entity_type_id, 'default')
       ->setComponent('field_test_text', array('type' => 'text_text'))
       ->save();
   }
 }
 
 /**
- * Implements hook_schema().
+ * Implements hook_uninstall().
  */
-function entity_test_schema() {
-  // Schema for simple entity.
-  $schema['entity_test'] = array(
-    'description' => 'Stores entity_test items.',
-    'fields' => array(
-      'id' => array(
-        'type' => 'serial',
-        'not null' => TRUE,
-        'description' => 'Primary Key: Unique entity-test item ID.',
-      ),
-      'uuid' => array(
-        'description' => 'Unique Key: Universally unique identifier for this entity.',
-        'type' => 'varchar',
-        'length' => 128,
-        'not null' => FALSE,
-      ),
-      'type' => array(
-        'description' => 'The bundle of the test entity.',
-        'type' => 'varchar',
-        'length' => 32,
-        'not null' => TRUE,
-        'default' => '',
-      ),
-      'langcode' => array(
-        'description' => 'The {language}.langcode of the original variant of this test entity.',
-        'type' => 'varchar',
-        'length' => 12,
-        'not null' => TRUE,
-        'default' => '',
-      ),
-      'name' => array(
-        'description' => 'The name of the test entity.',
-        'type' => 'varchar',
-        'length' => 32,
-        'not null' => TRUE,
-        'default' => '',
-      ),
-      'user_id' => array(
-        'type' => 'int',
-        'unsigned' => TRUE,
-        'not null' => FALSE,
-        'default' => NULL,
-        'description' => 'The {users}.uid of the associated user.',
-      ),
-    ),
-    'primary key' => array('id'),
-    'unique keys' => array(
-      'uuid' => array('uuid'),
-    ),
-  );
-
-  // Schema for entity with revisions.
-  $schema['entity_test_rev'] = array(
-    'description' => 'Stores entity_test_rev items.',
-    'fields' => array(
-      'id' => array(
-        'type' => 'serial',
-        'not null' => TRUE,
-        'description' => 'Primary Key: Unique entity-test item ID.',
-      ),
-      'revision_id' => array(
-        'description' => 'The current {entity_test_rev_property_revision}.revision_id version identifier.',
-        'type' => 'int',
-        'unsigned' => TRUE,
-        'not null' => TRUE,
-        'default' => 0,
-      ),
-      'uuid' => array(
-        'description' => 'Unique Key: Universally unique identifier for this entity.',
-        'type' => 'varchar',
-        'length' => 128,
-        'not null' => FALSE,
-      ),
-      'type' => array(
-        'description' => 'The bundle of the test entity.',
-        'type' => 'varchar',
-        'length' => 32,
-        'not null' => TRUE,
-        'default' => '',
-      ),
-      'name' => array(
-        'description' => 'The name of the test entity.',
-        'type' => 'varchar',
-        'length' => 32,
-        'not null' => TRUE,
-        'default' => '',
-      ),
-      'user_id' => array(
-        'type' => 'int',
-        'unsigned' => TRUE,
-        'not null' => FALSE,
-        'default' => NULL,
-        'description' => 'The {users}.uid of the associated user.',
-      ),
-    ),
-    'primary key' => array('id'),
-    'unique keys' => array(
-      'uuid' => array('uuid'),
-    ),
-  );
-  $schema['entity_test_rev_revision'] = array(
-    'description' => 'Stores entity_test_rev item property revisions.',
-    'fields' => array(
-      'id' => array(
-        'type' => 'int',
-        'unsigned' => TRUE,
-        'not null' => TRUE,
-        'description' => 'The {entity_test_rev}.id of the test entity.',
-      ),
-      'revision_id' => array(
-        'type' => 'serial',
-        'unsigned' => TRUE,
-        'not null' => TRUE,
-        'description' => 'The primary identifier for this version.',
-      ),
-      'langcode' => array(
-        'description' => 'The {language}.langcode of this variant of this test entity.',
-        'type' => 'varchar',
-        'length' => 12,
-        'not null' => TRUE,
-        'default' => '',
-      ),
-      'name' => array(
-        'description' => 'The name of the test entity.',
-        'type' => 'varchar',
-        'length' => 32,
-        'not null' => TRUE,
-        'default' => '',
-      ),
-      'user_id' => array(
-        'type' => 'int',
-        'unsigned' => TRUE,
-        'not null' => FALSE,
-        'default' => NULL,
-        'description' => 'The {users}.uid of the associated user.',
-      ),
-    ),
-    'indexes' => array(
-      'user_id' => array('user_id'),
-    ),
-    'foreign keys' => array(
-      'user_id' => array('users' => 'uid'),
-      'id' => array('entity_test_rev' => 'id'),
-    ),
-    'primary key' => array('revision_id'),
-  );
-
-  // Schema for entity with data table.
-  $schema['entity_test_mul'] = array(
-    'description' => 'Stores entity_test_mul items.',
-    'fields' => array(
-      'id' => array(
-        'type' => 'serial',
-        'not null' => TRUE,
-        'description' => 'Primary Key: Unique entity-test item ID.',
-      ),
-      'uuid' => array(
-        'description' => 'Unique Key: Universally unique identifier for this entity.',
-        'type' => 'varchar',
-        'length' => 128,
-        'not null' => FALSE,
-      ),
-      'type' => array(
-        'description' => 'The bundle of the test entity.',
-        'type' => 'varchar',
-        'length' => 32,
-        'not null' => TRUE,
-        'default' => '',
-      ),
-      'langcode' => array(
-        'description' => 'The {language}.langcode of the original variant of this test entity.',
-        'type' => 'varchar',
-        'length' => 12,
-        'not null' => TRUE,
-        'default' => '',
-      ),
-    ),
-    'primary key' => array('id'),
-    'unique keys' => array(
-      'uuid' => array('uuid'),
-    ),
-  );
-  $schema['entity_test_mul_property_data'] = array(
-    'description' => 'Stores entity_test_mul item properties.',
-    'fields' => array(
-      'id' => array(
-        'type' => 'int',
-        'unsigned' => TRUE,
-        'not null' => TRUE,
-        'description' => 'The {entity_test_mul}.id of the test entity.',
-      ),
-      'langcode' => array(
-        'description' => 'The {language}.langcode of this variant of this test entity.',
-        'type' => 'varchar',
-        'length' => 12,
-        'not null' => TRUE,
-        'default' => '',
-      ),
-      'default_langcode' => array(
-        'description' => 'Boolean indicating whether the current variant is in the original entity language.',
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => 1,
-      ),
-      'name' => array(
-        'description' => 'The name of the test entity.',
-        'type' => 'varchar',
-        'length' => 32,
-        'not null' => FALSE,
-      ),
-      'user_id' => array(
-        'type' => 'int',
-        'unsigned' => TRUE,
-        'not null' => FALSE,
-        'default' => NULL,
-        'description' => 'The {users}.uid of the associated user.',
-      ),
-    ),
-    'indexes' => array(
-      'user_id' => array('user_id'),
-    ),
-    'foreign keys' => array(
-      'user_id' => array('users' => 'uid'),
-      'id' => array('entity_test_mul' => 'id'),
-    ),
-    'primary key' => array('id', 'langcode'),
-  );
+function entity_test_uninstall() {
+  $entity_manager = \Drupal::entityManager();
 
-  // Schema for entity with data table and revisions.
-  $schema['entity_test_mulrev'] = array(
-    'description' => 'Stores entity_test_mulrev items.',
-    'fields' => array(
-      'id' => array(
-        'type' => 'serial',
-        'not null' => TRUE,
-        'description' => 'Primary Key: Unique entity-test item ID.',
-      ),
-      'revision_id' => array(
-        'description' => 'The current {entity_test_mulrev_property_revision}.revision_id version identifier.',
-        'type' => 'int',
-        'unsigned' => TRUE,
-        'not null' => TRUE,
-        'default' => 0,
-      ),
-      'uuid' => array(
-        'description' => 'Unique Key: Universally unique identifier for this entity.',
-        'type' => 'varchar',
-        'length' => 128,
-        'not null' => FALSE,
-      ),
-      'type' => array(
-        'description' => 'The bundle of the test entity.',
-        'type' => 'varchar',
-        'length' => 32,
-        'not null' => TRUE,
-        'default' => '',
-      ),
-    ),
-    'primary key' => array('id'),
-    'unique keys' => array(
-      'uuid' => array('uuid'),
-    ),
-  );
-  $schema['entity_test_mulrev_revision'] = array(
-    'description' => 'Stores entity_test_rev item property revisions.',
-    'fields' => array(
-      'id' => array(
-        'type' => 'int',
-        'unsigned' => TRUE,
-        'not null' => TRUE,
-        'description' => 'The {entity_test_rev}.id of the test entity.',
-      ),
-      'revision_id' => array(
-        'type' => 'serial',
-        'unsigned' => TRUE,
-        'not null' => TRUE,
-        'description' => 'The primary identifier for this version.',
-      ),
-      'langcode' => array(
-        'description' => 'The {language}.langcode of this variant of this test entity.',
-        'type' => 'varchar',
-        'length' => 12,
-        'not null' => TRUE,
-        'default' => '',
-      ),
-    ),
-    'foreign keys' => array(
-      'id' => array('entity_test_rev' => 'id'),
-    ),
-    'primary key' => array('revision_id'),
-  );
-  $schema['entity_test_mulrev_property_data'] = array(
-    'description' => 'Stores entity_test_mulrev item properties.',
-    'fields' => array(
-      'id' => array(
-        'type' => 'int',
-        'unsigned' => TRUE,
-        'not null' => TRUE,
-        'description' => 'The {entity_test_mulrev}.id of the test entity.',
-      ),
-      'revision_id' => array(
-        'description' => 'The current {entity_test_mulrev_property_revision}.revision_id version identifier.',
-        'type' => 'int',
-        'unsigned' => TRUE,
-        'not null' => TRUE,
-        'default' => 0,
-      ),
-      'langcode' => array(
-        'description' => 'The {language}.langcode of this variant of this test entity.',
-        'type' => 'varchar',
-        'length' => 12,
-        'not null' => TRUE,
-        'default' => '',
-      ),
-      'default_langcode' => array(
-        'description' => 'Boolean indicating whether the current variant is in the original entity language.',
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => 1,
-      ),
-      'name' => array(
-        'description' => 'The name of the test entity.',
-        'type' => 'varchar',
-        'length' => 32,
-        'not null' => TRUE,
-        'default' => '',
-      ),
-      'user_id' => array(
-        'type' => 'int',
-        'unsigned' => TRUE,
-        'not null' => FALSE,
-        'default' => NULL,
-        'description' => 'The {users}.uid of the associated user.',
-      ),
-    ),
-    'indexes' => array(
-      'user_id' => array('user_id'),
-    ),
-    'foreign keys' => array(
-      'user_id' => array('users' => 'uid'),
-      'id' => array('entity_test_mulrev' => 'id'),
-    ),
-    'primary key' => array('id', 'langcode'),
-  );
-  $schema['entity_test_mulrev_property_revision'] = array(
-    'description' => 'Stores entity_test_mulrev item property revisions.',
-    'fields' => array(
-      'id' => array(
-        'type' => 'int',
-        'unsigned' => TRUE,
-        'not null' => TRUE,
-        'description' => 'The {entity_test_mulrev}.id of the test entity.',
-      ),
-      'revision_id' => array(
-        'type' => 'int',
-        'unsigned' => TRUE,
-        'not null' => TRUE,
-        'description' => 'The primary identifier for this version.',
-      ),
-      'langcode' => array(
-        'description' => 'The {language}.langcode of this variant of this test entity.',
-        'type' => 'varchar',
-        'length' => 12,
-        'not null' => TRUE,
-        'default' => '',
-      ),
-      'default_langcode' => array(
-        'description' => 'Boolean indicating whether the current variant is in the original entity language.',
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => 1,
-      ),
-      'name' => array(
-        'description' => 'The name of the test entity.',
-        'type' => 'varchar',
-        'length' => 32,
-        'not null' => TRUE,
-        'default' => '',
-      ),
-      'user_id' => array(
-        'type' => 'int',
-        'unsigned' => TRUE,
-        'not null' => FALSE,
-        'default' => NULL,
-        'description' => 'The {users}.uid of the associated user.',
-      ),
-    ),
-    'indexes' => array(
-      'user_id' => array('user_id'),
-    ),
-    'foreign keys' => array(
-      'user_id' => array('users' => 'uid'),
-      'id' => array('entity_test_mulrev' => 'id'),
-    ),
-    'primary key' => array('revision_id', 'langcode'),
+  $entity_type_ids = array(
+    'entity_test',
+    'entity_test_rev',
+    'entity_test_mul',
+    'entity_test_mulrev',
   );
+  foreach ($entity_type_ids as $entity_type_id) {
+    $storage_controller = $entity_manager->getStorageController($entity_type_id);
 
-  return $schema;
+    // Install schema.
+    $storage_controller->deleteSchema();
+  }
 }
diff --git a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Entity/EntityTest.php b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Entity/EntityTest.php
index 72acdf2..88330b9 100644
--- a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Entity/EntityTest.php
+++ b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Entity/EntityTest.php
@@ -133,7 +133,8 @@ public static function baseFieldDefinitions($entity_type) {
     $fields['type'] = FieldDefinition::create('string')
       ->setLabel(t('Type'))
       ->setDescription(t('The bundle of the test entity.'))
-      ->setRequired(TRUE);
+      ->setRequired(TRUE)
+      ->setSetting('max_length', 32);
 
     $fields['user_id'] = FieldDefinition::create('entity_reference')
       ->setLabel(t('User ID'))
diff --git a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Entity/EntityTestLabelCallback.php b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Entity/EntityTestLabelCallback.php
index 481711f..e881b9a 100644
--- a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Entity/EntityTestLabelCallback.php
+++ b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Entity/EntityTestLabelCallback.php
@@ -15,7 +15,6 @@
  *   label = @Translation("Entity test label callback"),
  *   field_cache = FALSE,
  *   base_table = "entity_test",
- *   revision_table = "entity_test_revision",
  *   label_callback = "entity_test_label_callback",
  *   fieldable = TRUE,
  *   entity_keys = {
