diff --git a/core/lib/Drupal/Core/Entity/DatabaseStorageControllerNG.php b/core/lib/Drupal/Core/Entity/DatabaseStorageControllerNG.php
index fd8248e1c7c9cd911de2ed624746fc95581dc218..3ccc88d5fc32548ee7c2ecbdb030cdebf2645ed1 100644
--- a/core/lib/Drupal/Core/Entity/DatabaseStorageControllerNG.php
+++ b/core/lib/Drupal/Core/Entity/DatabaseStorageControllerNG.php
@@ -9,6 +9,7 @@
 
 use PDO;
 
+use Drupal\Core\Entity\Query\QueryInterface;
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Entity\DatabaseStorageController;
 use Drupal\Core\Entity\EntityStorageException;
@@ -36,6 +37,13 @@ class DatabaseStorageControllerNG extends DatabaseStorageController {
    */
   protected $bundleKey;
 
+  /**
+   * The table that stores properties, if the entity has multilingual support.
+   *
+   * @var string
+   */
+  protected $dataTable;
+
   /**
    * Overrides DatabaseStorageController::__construct().
    */
@@ -44,6 +52,11 @@ public function __construct($entityType) {
     $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().
@@ -94,6 +107,34 @@ public function create(array $values) {
     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);
+  }
+
   /**
    * Overrides DatabaseStorageController::attachLoad().
    *
@@ -146,7 +187,7 @@ protected function attachLoad(&$queried_entities, $load_revision = FALSE) {
    *   An array of entity objects implementing the EntityInterface.
    */
   protected function mapFromStorageRecords(array $records, $load_revision = FALSE) {
-
+    $entities = array();
     foreach ($records as $id => $record) {
       $values = array();
       foreach ($record as $name => $value) {
@@ -155,9 +196,59 @@ protected function mapFromStorageRecords(array $records, $load_revision = FALSE)
       }
       $bundle = $this->bundleKey ? $record->{$this->bundleKey} : FALSE;
       // Turn the record into an entity class.
-      $records[$id] = new $this->entityClass($values, $this->entityType, $bundle);
+      $entities[$id] = new $this->entityClass($values, $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 boolean $load_revision
+   *   (optional) TRUE if the revision should be loaded, defaults to FALSE.
+   */
+  protected function attachPropertyData(array &$entities, $load_revision = FALSE) {
+    if ($this->dataTable) {
+      $query = db_select($this->dataTable, 'data', array('fetch' => PDO::FETCH_ASSOC))
+        ->fields('data')
+        ->condition($this->idKey, array_keys($entities))
+        ->orderBy('data.' . $this->idKey);
+      if ($load_revision) {
+        // Get revision ID's.
+        $revision_ids = array();
+        foreach ($entities as $id => $entity) {
+          $revision_ids[] = $entity->get($this->revisionKey)->value;
+        }
+        $query->condition($this->revisionKey, $revision_ids);
+      }
+      $data = $query->execute();
+
+      // Fetch the field definitions to check which field is translatable.
+      $field_definition = $this->getFieldDefinitions(array());
+      $data_fields = array_flip($this->entityInfo['schema_fields_sql']['data_table']);
+
+      foreach ($data as $values) {
+        $id = $values[$this->idKey];
+        // Field values in default language are stored with LANGUAGE_DEFAULT as
+        // key.
+        $langcode = empty($values['default_langcode']) ? $values['langcode'] : LANGUAGE_DEFAULT;
+        $translation = $entities[$id]->getTranslation($langcode);
+
+        foreach ($field_definition as $name => $definition) {
+          // Set translatable properties only.
+          if (isset($data_fields[$name]) && !empty($definition['translatable'])) {
+            $translation->{$name}->value = $values[$name];
+          }
+          // Avoid initializing configurable fields before loading them.
+          elseif (!empty($definition['configurable'])) {
+            unset($entities[$id]->fields[$name]);
+          }
+        }
+      }
     }
-    return $records;
   }
 
   /**
@@ -191,6 +282,9 @@ public function save(EntityInterface $entity) {
         if ($this->revisionKey) {
           $record->{$this->revisionKey} = $this->saveRevision($entity);
         }
+        if ($this->dataTable) {
+          $this->savePropertyData($entity);
+        }
         $this->resetCache(array($entity->id()));
         $this->postSave($entity, TRUE);
         $this->invokeHook('update', $entity);
@@ -201,10 +295,14 @@ public function save(EntityInterface $entity) {
           $entity->{$this->idKey}->value = $record->{$this->idKey};
           $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->{$this->idKey}->value = $record->{$this->idKey};
         $entity->enforceIsNew(FALSE);
         $this->postSave($entity, FALSE);
         $this->invokeHook('insert', $entity);
@@ -262,6 +360,31 @@ protected function saveRevision(EntityInterface $entity) {
     return $record->{$this->revisionKey};
   }
 
+  /**
+   * 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.
+    db_delete($this->dataTable)
+      ->condition($this->idKey, $entity->id())
+      ->execute();
+
+    $query = db_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();
+  }
+
   /**
    * Overrides DatabaseStorageController::invokeHook().
    *
@@ -286,6 +409,12 @@ protected function invokeHook($hook, EntityInterface $entity) {
 
   /**
    * 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();
@@ -297,6 +426,12 @@ protected function mapToStorageRecord(EntityInterface $entity) {
 
   /**
    * 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();
@@ -305,4 +440,81 @@ protected function mapToRevisionStorageRecord(EntityInterface $entity) {
     }
     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->language()->langcode;
+    // 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, FALSE);
+
+    $record = new \stdClass();
+    foreach ($this->entityInfo['schema_fields_sql']['data_table'] as $name) {
+      $record->$name = $translation->$name->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 = db_transaction();
+    try {
+      $this->preDelete($entities);
+      foreach ($entities as $id => $entity) {
+        $this->invokeHook('predelete', $entity);
+      }
+      $ids = array_keys($entities);
+
+      db_delete($this->entityInfo['base_table'])
+        ->condition($this->idKey, $ids)
+        ->execute();
+
+      if ($this->revisionKey) {
+        db_delete($this->revisionTable)
+          ->condition($this->idKey, $ids)
+          ->execute();
+      }
+
+      if ($this->dataTable) {
+        db_delete($this->dataTable)
+          ->condition($this->idKey, $ids)
+          ->execute();
+      }
+
+      // Reset the cache as soon as the changes have been applied.
+      $this->resetCache($ids);
+
+      $this->postDelete($entities);
+      foreach ($entities as $id => $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/EntityFormController.php b/core/lib/Drupal/Core/Entity/EntityFormController.php
index 0b3057e01d752e14a739705b60c3cc0e0154338c..4d29556ba2e3d4c59448224dac5fcad5caff09d6 100644
--- a/core/lib/Drupal/Core/Entity/EntityFormController.php
+++ b/core/lib/Drupal/Core/Entity/EntityFormController.php
@@ -187,6 +187,7 @@ public function submit(array $form, array &$form_state) {
     // Remove button and internal Form API values from submitted values.
     form_state_values_clean($form_state);
 
+    $this->updateFormLangcode($form_state);
     $this->submitEntityLanguage($form, $form_state);
     $entity = $this->buildEntity($form, $form_state);
     $this->setEntity($entity, $form_state);
@@ -246,24 +247,32 @@ public function getFormLangcode(array $form_state) {
   /**
    * Implements EntityFormControllerInterface::isDefaultFormLangcode().
    */
-  public function isDefaultFormLangcode($form_state) {
+  public function isDefaultFormLangcode(array $form_state) {
     return $this->getFormLangcode($form_state) == $this->getEntity($form_state)->language()->langcode;
   }
 
   /**
-   * Handle possible entity language changes.
+   * Updates the form language to reflect any change to the entity language.
    *
-   * @param array $form
-   *   An associative array containing the structure of the form.
    * @param array $form_state
-   *   A reference to a keyed array containing the current state of the form.
+   *   A keyed array containing the current state of the form.
    */
-  protected function submitEntityLanguage(array $form, array &$form_state) {
+  protected function updateFormLangcode(array $form_state) {
     // Update the form language as it might have changed.
     if (isset($form_state['values']['langcode']) && $this->isDefaultFormLangcode($form_state)) {
       $form_state['langcode'] = $form_state['values']['langcode'];
     }
+  }
 
+  /**
+   * Handle possible entity language changes.
+   *
+   * @param array $form
+   *   An associative array containing the structure of the form.
+   * @param array $form_state
+   *   A reference to a keyed array containing the current state of the form.
+   */
+  protected function submitEntityLanguage(array $form, array &$form_state) {
     $entity = $this->getEntity($form_state);
     $entity_type = $entity->entityType();
 
diff --git a/core/lib/Drupal/Core/Entity/EntityFormControllerInterface.php b/core/lib/Drupal/Core/Entity/EntityFormControllerInterface.php
index fecb0783ff192f509d9e08bfef8ea027a8656ab2..f2ddac2b8af2689f0598cd05ff548be8e30b83a6 100644
--- a/core/lib/Drupal/Core/Entity/EntityFormControllerInterface.php
+++ b/core/lib/Drupal/Core/Entity/EntityFormControllerInterface.php
@@ -47,12 +47,12 @@ public function getFormLangcode(array $form_state);
    * Checks whether the current form language matches the entity one.
    *
    * @param array $form_state
-   *   A reference to a keyed array containing the current state of the form.
+   *   A keyed array containing the current state of the form.
    *
    * @return boolean
    *   Returns TRUE if the entity form language matches the entity one.
    */
-  public function isDefaultFormLangcode($form_state);
+  public function isDefaultFormLangcode(array $form_state);
 
   /**
    * Returns the operation identifying the form controller.
diff --git a/core/lib/Drupal/Core/Entity/EntityFormControllerNG.php b/core/lib/Drupal/Core/Entity/EntityFormControllerNG.php
index 53667a501df3b7147d92c1eed31b12fe2284f5f0..02c07c5d528fd04a37ceda7af8590e60a9e13312 100644
--- a/core/lib/Drupal/Core/Entity/EntityFormControllerNG.php
+++ b/core/lib/Drupal/Core/Entity/EntityFormControllerNG.php
@@ -47,6 +47,16 @@ public function validate(array $form, array &$form_state) {
     form_execute_handlers('validate', $form, $form_state);
   }
 
+  /**
+   * Overrides EntityFormController::submitEntityLanguage().
+   */
+  protected function submitEntityLanguage(array $form, array &$form_state) {
+    // Nothing to do here, as original field values are always stored with
+    // LANGUAGE_DEFAULT language.
+    // @todo Delete this method when merging EntityFormControllerNG with
+    //   EntityFormController.
+  }
+
   /**
    * Overrides EntityFormController::buildEntity().
    */
diff --git a/core/lib/Drupal/Core/Entity/EntityManager.php b/core/lib/Drupal/Core/Entity/EntityManager.php
index caf46a256cfa9bb6820f0eebeac6a2bbaef37120..affdd80726ee44dc536dc14fcbd58621a3c452a1 100644
--- a/core/lib/Drupal/Core/Entity/EntityManager.php
+++ b/core/lib/Drupal/Core/Entity/EntityManager.php
@@ -294,6 +294,9 @@ public function processDefinition(&$definition, $plugin_id) {
     // Drupal\Core\Entity\DatabaseStorageControllerInterface::buildQuery().
     if (isset($definition['base_table'])) {
       $definition['schema_fields_sql']['base_table'] = drupal_schema_fields_sql($definition['base_table']);
+      if (isset($definition['data_table'])) {
+        $definition['schema_fields_sql']['data_table'] = drupal_schema_fields_sql($definition['data_table']);
+      }
       if (isset($definition['revision_table'])) {
         $definition['schema_fields_sql']['revision_table'] = drupal_schema_fields_sql($definition['revision_table']);
       }
diff --git a/core/lib/Drupal/Core/Entity/EntityNG.php b/core/lib/Drupal/Core/Entity/EntityNG.php
index 7df5b1e787fa66f2bf6777fe9b6f6e7bc3853050..b798bcf898e3d79986bdf197c896929b07d572d9 100644
--- a/core/lib/Drupal/Core/Entity/EntityNG.php
+++ b/core/lib/Drupal/Core/Entity/EntityNG.php
@@ -102,7 +102,7 @@ protected function init() {
   }
 
   /**
-   * Magic __wakeup() implemenation.
+   * Magic __wakeup() implementation.
    */
   public function __wakeup() {
     $this->init();
diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityApiTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityApiTest.php
index 7cf3403ac3b89b63593af5f747fe2bf06cccab5a..4c428cca27273d2eab0518aaa42816d472683d62 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityApiTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityApiTest.php
@@ -32,43 +32,58 @@ public static function getInfo() {
   /**
    * Tests basic CRUD functionality of the Entity API.
    */
-  function testCRUD() {
+  public function testCRUD() {
     $user1 = $this->drupalCreateUser();
 
+    // All entity variations have to have the same results.
+    foreach (entity_test_entity_types() as $entity_type) {
+      $this->assertCRUD($entity_type, $user1);
+    }
+  }
+
+  /**
+   * Executes a test set for a defined entity type and user.
+   *
+   * @param string $entity_type
+   *   The entity type to run the tests with.
+   * @param \Drupal\user\Plugin\Core\Entity\User $user1
+   *   The user to run the tests with.
+   */
+  protected function assertCRUD($entity_type, \Drupal\user\Plugin\Core\Entity\User $user1) {
     // Create some test entities.
-    $entity = entity_create('entity_test', array('name' => 'test', 'user_id' => $user1->uid));
+    $entity = entity_create($entity_type, array('name' => 'test', 'user_id' => $user1->uid));
     $entity->save();
-    $entity = entity_create('entity_test', array('name' => 'test2', 'user_id' => $user1->uid));
+    $entity = entity_create($entity_type, array('name' => 'test2', 'user_id' => $user1->uid));
     $entity->save();
-    $entity = entity_create('entity_test', array('name' => 'test', 'user_id' => NULL));
+    $entity = entity_create($entity_type, array('name' => 'test', 'user_id' => NULL));
     $entity->save();
 
-    $entities = array_values(entity_load_multiple_by_properties('entity_test', array('name' => 'test')));
-    $this->assertEqual($entities[0]->name->value, 'test', 'Created and loaded entity.');
-    $this->assertEqual($entities[1]->name->value, 'test', 'Created and loaded entity.');
+    $entities = array_values(entity_load_multiple_by_properties($entity_type, array('name' => 'test')));
+    $this->assertEqual($entities[0]->name->value, 'test', format_string('%entity_type: Created and loaded entity', array('%entity_type' => $entity_type)));
+    $this->assertEqual($entities[1]->name->value, 'test', format_string('%entity_type: Created and loaded entity', array('%entity_type' => $entity_type)));
 
     // Test loading a single entity.
-    $loaded_entity = entity_test_load($entity->id());
-    $this->assertEqual($loaded_entity->id(), $entity->id(), 'Loaded a single entity by id.');
+    $loaded_entity = entity_load($entity_type, $entity->id());
+    $this->assertEqual($loaded_entity->id(), $entity->id(), format_string('%entity_type: Loaded a single entity by id.', array('%entity_type' => $entity_type)));
 
     // Test deleting an entity.
-    $entities = array_values(entity_load_multiple_by_properties('entity_test', array('name' => 'test2')));
+    $entities = array_values(entity_load_multiple_by_properties($entity_type, array('name' => 'test2')));
     $entities[0]->delete();
-    $entities = array_values(entity_load_multiple_by_properties('entity_test', array('name' => 'test2')));
-    $this->assertEqual($entities, array(), 'Entity deleted.');
+    $entities = array_values(entity_load_multiple_by_properties($entity_type, array('name' => 'test2')));
+    $this->assertEqual($entities, array(), format_string('%entity_type: Entity deleted.', array('%entity_type' => $entity_type)));
 
     // Test updating an entity.
-    $entities = array_values(entity_load_multiple_by_properties('entity_test', array('name' => 'test')));
+    $entities = array_values(entity_load_multiple_by_properties($entity_type, array('name' => 'test')));
     $entities[0]->name->value = 'test3';
     $entities[0]->save();
-    $entity = entity_test_load($entities[0]->id());
-    $this->assertEqual($entity->name->value, 'test3', 'Entity updated.');
+    $entity = entity_load($entity_type, $entities[0]->id());
+    $this->assertEqual($entity->name->value, 'test3', format_string('%entity_type: Entity updated.', array('%entity_type' => $entity_type)));
 
     // Try deleting multiple test entities by deleting all.
-    $ids = array_keys(entity_test_load_multiple());
-    entity_test_delete_multiple($ids);
+    $ids = array_keys(entity_load_multiple($entity_type));
+    entity_delete_multiple($entity_type, $ids);
 
-    $all = entity_test_load_multiple();
-    $this->assertTrue(empty($all), 'Deleted all entities.');
+    $all = entity_load_multiple($entity_type);
+    $this->assertTrue(empty($all), format_string('%entity_type: Deleted all entities.', array('%entity_type' => $entity_type)));
   }
 }
diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityFieldTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityFieldTest.php
index 19838f978edd63bd2b0171d3645aae743a3faffb..f01d4404ba2d0012d0256d019ba2ff376df67586 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityFieldTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityFieldTest.php
@@ -38,14 +38,14 @@ public static function getInfo() {
    *
    * @return \Drupal\Core\Entity\EntityInterface
    */
-  protected function createTestEntity() {
+  protected function createTestEntity($entity_type) {
     $this->entity_name = $this->randomName();
     $this->entity_user = $this->drupalCreateUser();
     $this->entity_field_text = $this->randomName();
 
     // Pass in the value of the name field when creating. With the user
     // field we test setting a field after creation.
-    $entity = entity_create('entity_test', array());
+    $entity = entity_create($entity_type, array());
     $entity->user_id->value = $this->entity_user->uid;
     $entity->name->value = $this->entity_name;
 
@@ -59,74 +59,87 @@ protected function createTestEntity() {
    * Tests reading and writing properties and field items.
    */
   public function testReadWrite() {
-    $entity = $this->createTestEntity();
+    // All entity variations have to have the same results.
+    foreach (entity_test_entity_types() as $entity_type) {
+      $this->assertReadWrite($entity_type);
+    }
+  }
+
+  /**
+   * Executes the read write test set for a defined entity type.
+   *
+   * @param string $entity_type
+   *   The entity type to run the tests with.
+   */
+  protected function assertReadWrite($entity_type) {
+    $entity = $this->createTestEntity($entity_type);
 
     // Access the name field.
-    $this->assertTrue($entity->name instanceof FieldInterface, 'Field implements interface');
-    $this->assertTrue($entity->name[0] instanceof FieldItemInterface, 'Field item implements interface');
+    $this->assertTrue($entity->name instanceof FieldInterface, format_string('%entity_type: Field implements interface', array('%entity_type' => $entity_type)));
+    $this->assertTrue($entity->name[0] instanceof FieldItemInterface, format_string('%entity_type: Field item implements interface', array('%entity_type' => $entity_type)));
 
-    $this->assertEqual($this->entity_name, $entity->name->value, 'Name value can be read.');
-    $this->assertEqual($this->entity_name, $entity->name[0]->value, 'Name value can be read through list access.');
-    $this->assertEqual($entity->name->getValue(), array(0 => array('value' => $this->entity_name)), 'Plain field value returned.');
+    $this->assertEqual($this->entity_name, $entity->name->value, format_string('%entity_type: Name value can be read.', array('%entity_type' => $entity_type)));
+    $this->assertEqual($this->entity_name, $entity->name[0]->value, format_string('%entity_type: Name value can be read through list access.', array('%entity_type' => $entity_type)));
+    $this->assertEqual($entity->name->getValue(), array(0 => array('value' => $this->entity_name)), format_string('%entity_type: Plain field value returned.', array('%entity_type' => $entity_type)));
 
     // Change the name.
     $new_name = $this->randomName();
     $entity->name->value = $new_name;
-    $this->assertEqual($new_name, $entity->name->value, 'Name can be updated and read.');
-    $this->assertEqual($entity->name->getValue(), array(0 => array('value' => $new_name)), 'Plain field value reflects the update.');
+    $this->assertEqual($new_name, $entity->name->value, format_string('%entity_type: Name can be updated and read.', array('%entity_type' => $entity_type)));
+    $this->assertEqual($entity->name->getValue(), array(0 => array('value' => $new_name)), format_string('%entity_type: Plain field value reflects the update.', array('%entity_type' => $entity_type)));
 
     $new_name = $this->randomName();
     $entity->name[0]->value = $new_name;
-    $this->assertEqual($new_name, $entity->name->value, 'Name can be updated and read through list access.');
+    $this->assertEqual($new_name, $entity->name->value, format_string('%entity_type: Name can be updated and read through list access.', array('%entity_type' => $entity_type)));
 
     // Access the user field.
-    $this->assertTrue($entity->user_id instanceof FieldInterface, 'Field implements interface');
-    $this->assertTrue($entity->user_id[0] instanceof FieldItemInterface, 'Field item implements interface');
+    $this->assertTrue($entity->user_id instanceof FieldInterface, format_string('%entity_type: Field implements interface', array('%entity_type' => $entity_type)));
+    $this->assertTrue($entity->user_id[0] instanceof FieldItemInterface, format_string('%entity_type: Field item implements interface', array('%entity_type' => $entity_type)));
 
-    $this->assertEqual($this->entity_user->uid, $entity->user_id->value, 'User id can be read.');
-    $this->assertEqual($this->entity_user->name, $entity->user_id->entity->name, 'User name can be read.');
+    $this->assertEqual($this->entity_user->uid, $entity->user_id->value, format_string('%entity_type: User id can be read.', array('%entity_type' => $entity_type)));
+    $this->assertEqual($this->entity_user->name, $entity->user_id->entity->name, format_string('%entity_type: User name can be read.', array('%entity_type' => $entity_type)));
 
     // Change the assigned user by entity.
     $new_user = $this->drupalCreateUser();
     $entity->user_id->entity = $new_user;
-    $this->assertEqual($new_user->uid, $entity->user_id->value, 'Updated user id can be read.');
-    $this->assertEqual($new_user->name, $entity->user_id->entity->name, 'Updated user name value can be read.');
+    $this->assertEqual($new_user->uid, $entity->user_id->value, format_string('%entity_type: Updated user id can be read.', array('%entity_type' => $entity_type)));
+    $this->assertEqual($new_user->name, $entity->user_id->entity->name, format_string('%entity_type: Updated user name value can be read.', array('%entity_type' => $entity_type)));
 
     // Change the assigned user by id.
     $new_user = $this->drupalCreateUser();
     $entity->user_id->value = $new_user->uid;
-    $this->assertEqual($new_user->uid, $entity->user_id->value, 'Updated user id can be read.');
-    $this->assertEqual($new_user->name, $entity->user_id->entity->name, 'Updated user name value can be read.');
+    $this->assertEqual($new_user->uid, $entity->user_id->value, format_string('%entity_type: Updated user id can be read.', array('%entity_type' => $entity_type)));
+    $this->assertEqual($new_user->name, $entity->user_id->entity->name, format_string('%entity_type: Updated user name value can be read.', array('%entity_type' => $entity_type)));
 
     // Try unsetting a field.
     $entity->name->value = NULL;
     $entity->user_id->value = NULL;
-    $this->assertNull($entity->name->value, 'Name field is not set.');
-    $this->assertNull($entity->user_id->value, 'User ID field is not set.');
-    $this->assertNull($entity->user_id->entity, 'User entity field is not set.');
+    $this->assertNull($entity->name->value, format_string('%entity_type: Name field is not set.', array('%entity_type' => $entity_type)));
+    $this->assertNull($entity->user_id->value, format_string('%entity_type: User ID field is not set.', array('%entity_type' => $entity_type)));
+    $this->assertNull($entity->user_id->entity, format_string('%entity_type: User entity field is not set.', array('%entity_type' => $entity_type)));
 
     // Test using isset(), empty() and unset().
     $entity->name->value = 'test unset';
     unset($entity->name->value);
-    $this->assertFalse(isset($entity->name->value), 'Name is not set.');
-    $this->assertFalse(isset($entity->name[0]->value), 'Name is not set.');
-    $this->assertTrue(empty($entity->name->value), 'Name is empty.');
-    $this->assertTrue(empty($entity->name[0]->value), 'Name is empty.');
+    $this->assertFalse(isset($entity->name->value), format_string('%entity_type: Name is not set.', array('%entity_type' => $entity_type)));
+    $this->assertFalse(isset($entity->name[0]->value), format_string('%entity_type: Name is not set.', array('%entity_type' => $entity_type)));
+    $this->assertTrue(empty($entity->name->value), format_string('%entity_type: Name is empty.', array('%entity_type' => $entity_type)));
+    $this->assertTrue(empty($entity->name[0]->value), format_string('%entity_type: Name is empty.', array('%entity_type' => $entity_type)));
 
     $entity->name->value = 'a value';
-    $this->assertTrue(isset($entity->name->value), 'Name is set.');
-    $this->assertTrue(isset($entity->name[0]->value), 'Name is set.');
-    $this->assertFalse(empty($entity->name->value), 'Name is not empty.');
-    $this->assertFalse(empty($entity->name[0]->value), 'Name is not empty.');
-    $this->assertTrue(isset($entity->name[0]), 'Name string item is set.');
-    $this->assertFalse(isset($entity->name[1]), 'Second name string item is not set as it does not exist');
-    $this->assertTrue(isset($entity->name), 'Name field is set.');
-    $this->assertFalse(isset($entity->nameInvalid), 'Not existing field is not set.');
+    $this->assertTrue(isset($entity->name->value), format_string('%entity_type: Name is set.', array('%entity_type' => $entity_type)));
+    $this->assertTrue(isset($entity->name[0]->value), format_string('%entity_type: Name is set.', array('%entity_type' => $entity_type)));
+    $this->assertFalse(empty($entity->name->value), format_string('%entity_type: Name is not empty.', array('%entity_type' => $entity_type)));
+    $this->assertFalse(empty($entity->name[0]->value), format_string('%entity_type: Name is not empty.', array('%entity_type' => $entity_type)));
+    $this->assertTrue(isset($entity->name[0]), format_string('%entity_type: Name string item is set.', array('%entity_type' => $entity_type)));
+    $this->assertFalse(isset($entity->name[1]), format_string('%entity_type: Second name string item is not set as it does not exist', array('%entity_type' => $entity_type)));
+    $this->assertTrue(isset($entity->name), format_string('%entity_type: Name field is set.', array('%entity_type' => $entity_type)));
+    $this->assertFalse(isset($entity->nameInvalid), format_string('%entity_type: Not existing field is not set.', array('%entity_type' => $entity_type)));
 
     unset($entity->name[0]);
-    $this->assertFalse(isset($entity->name[0]), 'Name field item is not set.');
-    $this->assertFalse(isset($entity->name[0]->value), 'Name is not set.');
-    $this->assertFalse(isset($entity->name->value), 'Name is not set.');
+    $this->assertFalse(isset($entity->name[0]), format_string('%entity_type: Name field item is not set.', array('%entity_type' => $entity_type)));
+    $this->assertFalse(isset($entity->name[0]->value), format_string('%entity_type: Name is not set.', array('%entity_type' => $entity_type)));
+    $this->assertFalse(isset($entity->name->value), format_string('%entity_type: Name is not set.', array('%entity_type' => $entity_type)));
 
     $entity->name = array();
     $this->assertTrue(isset($entity->name), 'Name field is set.');
@@ -141,33 +154,33 @@ public function testReadWrite() {
     $this->assertFalse(isset($entity->name->value), 'Name value is not set.');
 
     $entity->name->value = 'a value';
-    $this->assertTrue(isset($entity->name->value), 'Name is set.');
+    $this->assertTrue(isset($entity->name->value), format_string('%entity_type: Name is set.', array('%entity_type' => $entity_type)));
     unset($entity->name);
-    $this->assertFalse(isset($entity->name), 'Name field is not set.');
-    $this->assertFalse(isset($entity->name[0]), 'Name field item is not set.');
-    $this->assertFalse(isset($entity->name[0]->value), 'Name is not set.');
-    $this->assertFalse(isset($entity->name->value), 'Name is not set.');
+    $this->assertFalse(isset($entity->name), format_string('%entity_type: Name field is not set.', array('%entity_type' => $entity_type)));
+    $this->assertFalse(isset($entity->name[0]), format_string('%entity_type: Name field item is not set.', array('%entity_type' => $entity_type)));
+    $this->assertFalse(isset($entity->name[0]->value), format_string('%entity_type: Name is not set.', array('%entity_type' => $entity_type)));
+    $this->assertFalse(isset($entity->name->value), format_string('%entity_type: Name is not set.', array('%entity_type' => $entity_type)));
 
     // Access the language field.
-    $this->assertEqual(LANGUAGE_NOT_SPECIFIED, $entity->langcode->value, 'Language code can be read.');
-    $this->assertEqual(language_load(LANGUAGE_NOT_SPECIFIED), $entity->langcode->language, 'Language object can be read.');
+    $this->assertEqual(LANGUAGE_NOT_SPECIFIED, $entity->langcode->value, format_string('%entity_type: Language code can be read.', array('%entity_type' => $entity_type)));
+    $this->assertEqual(language_load(LANGUAGE_NOT_SPECIFIED), $entity->langcode->language, format_string('%entity_type: Language object can be read.', array('%entity_type' => $entity_type)));
 
     // Change the language by code.
     $entity->langcode->value = language_default()->langcode;
-    $this->assertEqual(language_default()->langcode, $entity->langcode->value, 'Language code can be read.');
-    $this->assertEqual(language_default(), $entity->langcode->language, 'Language object can be read.');
+    $this->assertEqual(language_default()->langcode, $entity->langcode->value, format_string('%entity_type: Language code can be read.', array('%entity_type' => $entity_type)));
+    $this->assertEqual(language_default(), $entity->langcode->language, format_string('%entity_type: Language object can be read.', array('%entity_type' => $entity_type)));
 
     // Revert language by code then try setting it by language object.
     $entity->langcode->value = LANGUAGE_NOT_SPECIFIED;
     $entity->langcode->language = language_default();
-    $this->assertEqual(language_default()->langcode, $entity->langcode->value, 'Language code can be read.');
-    $this->assertEqual(language_default(), $entity->langcode->language, 'Language object can be read.');
+    $this->assertEqual(language_default()->langcode, $entity->langcode->value, format_string('%entity_type: Language code can be read.', array('%entity_type' => $entity_type)));
+    $this->assertEqual(language_default(), $entity->langcode->language, format_string('%entity_type: Language object can be read.', array('%entity_type' => $entity_type)));
 
     // Access the text field and test updating.
-    $this->assertEqual($entity->field_test_text->value, $this->entity_field_text, 'Text field can be read.');
+    $this->assertEqual($entity->field_test_text->value, $this->entity_field_text, format_string('%entity_type: Text field can be read.', array('%entity_type' => $entity_type)));
     $new_text = $this->randomName();
     $entity->field_test_text->value = $new_text;
-    $this->assertEqual($entity->field_test_text->value, $new_text, 'Updated text field can be read.');
+    $this->assertEqual($entity->field_test_text->value, $new_text, format_string('%entity_type: Updated text field can be read.', array('%entity_type' => $entity_type)));
 
     // Test creating the entity by passing in plain values.
     $this->entity_name = $this->randomName();
@@ -177,153 +190,179 @@ public function testReadWrite() {
     $this->entity_field_text = $this->randomName();
     $text_item[0]['value'] = $this->entity_field_text;
 
-    $entity = entity_create('entity_test', array(
+    $entity = entity_create($entity_type, array(
       'name' => $name_item,
       'user_id' => $user_item,
       'field_test_text' => $text_item,
     ));
-    $this->assertEqual($this->entity_name, $entity->name->value, 'Name value can be read.');
-    $this->assertEqual($this->entity_user->uid, $entity->user_id->value, 'User id can be read.');
-    $this->assertEqual($this->entity_user->name, $entity->user_id->entity->name, 'User name can be read.');
-    $this->assertEqual($this->entity_field_text, $entity->field_test_text->value, 'Text field can be read.');
+    $this->assertEqual($this->entity_name, $entity->name->value, format_string('%entity_type: Name value can be read.', array('%entity_type' => $entity_type)));
+    $this->assertEqual($this->entity_user->uid, $entity->user_id->value, format_string('%entity_type: User id can be read.', array('%entity_type' => $entity_type)));
+    $this->assertEqual($this->entity_user->name, $entity->user_id->entity->name, format_string('%entity_type: User name can be read.', array('%entity_type' => $entity_type)));
+    $this->assertEqual($this->entity_field_text, $entity->field_test_text->value, format_string('%entity_type: Text field can be read.', array('%entity_type' => $entity_type)));
 
     // Test copying field values.
-    $entity2 = $this->createTestEntity();
+    $entity2 = $this->createTestEntity($entity_type);
     $entity2->name = $entity->name;
     $entity2->user_id = $entity->user_id;
     $entity2->field_test_text = $entity->field_test_text;
 
-    $this->assertTrue($entity->name !== $entity2->name, 'Copying properties results in a different field object.');
-    $this->assertEqual($entity->name->value, $entity2->name->value, 'Name field copied.');
-    $this->assertEqual($entity->user_id->value, $entity2->user_id->value, 'User id field copied.');
-    $this->assertEqual($entity->field_test_text->value, $entity2->field_test_text->value, 'Text field copied.');
+    $this->assertTrue($entity->name !== $entity2->name, format_string('%entity_type: Copying properties results in a different field object.', array('%entity_type' => $entity_type)));
+    $this->assertEqual($entity->name->value, $entity2->name->value, format_string('%entity_type: Name field copied.', array('%entity_type' => $entity_type)));
+    $this->assertEqual($entity->user_id->value, $entity2->user_id->value, format_string('%entity_type: User id field copied.', array('%entity_type' => $entity_type)));
+    $this->assertEqual($entity->field_test_text->value, $entity2->field_test_text->value, format_string('%entity_type: Text field copied.', array('%entity_type' => $entity_type)));
 
     // Tests adding a value to a field item list.
     $entity->name[] = 'Another name';
-    $this->assertEqual($entity->name[1]->value == 'Another name', 'List item added via [].');
+    $this->assertEqual($entity->name[1]->value == 'Another name', format_string('%entity_type: List item added via [].', array('%entity_type' => $entity_type)));
     $entity->name[2]->value = 'Third name';
-    $this->assertEqual($entity->name[2]->value == 'Third name', 'List item added by a accessing not yet created item.');
+    $this->assertEqual($entity->name[2]->value == 'Third name', format_string('%entity_type: List item added by a accessing not yet created item.', array('%entity_type' => $entity_type)));
 
     // Test removing and empty-ing list items.
-    $this->assertEqual(count($entity->name), 3, 'List has 3 items.');
+    $this->assertEqual(count($entity->name), 3, format_string('%entity_type: List has 3 items.', array('%entity_type' => $entity_type)));
     unset($entity->name[1]);
-    $this->assertEqual(count($entity->name), 2, 'Second list item has been removed.');
+    $this->assertEqual(count($entity->name), 2, format_string('%entity_type: Second list item has been removed.', array('%entity_type' => $entity_type)));
     $entity->name[2] = NULL;
-    $this->assertEqual(count($entity->name), 2, 'Assigning NULL does not reduce array count.');
-    $this->assertTrue($entity->name[2]->isEmpty(), 'Assigning NULL empties the item.');
+    $this->assertEqual(count($entity->name), 2, format_string('%entity_type: Assigning NULL does not reduce array count.', array('%entity_type' => $entity_type)));
+    $this->assertTrue($entity->name[2]->isEmpty(), format_string('%entity_type: Assigning NULL empties the item.', array('%entity_type' => $entity_type)));
 
     // Test using isEmpty().
     unset($entity->name[2]);
-    $this->assertFalse($entity->name[0]->isEmpty(), 'Name item is not empty.');
+    $this->assertFalse($entity->name[0]->isEmpty(), format_string('%entity_type: Name item is not empty.', array('%entity_type' => $entity_type)));
     $entity->name->value = NULL;
-    $this->assertTrue($entity->name[0]->isEmpty(), 'Name item is empty.');
-    $this->assertTrue($entity->name->isEmpty(), 'Name field is empty.');
-    $this->assertEqual(count($entity->name), 1, 'Empty item is considered when counting.');
-    $this->assertEqual(count(iterator_to_array($entity->name->getIterator())), count($entity->name), 'Count matches iterator count.');
-    $this->assertTrue($entity->name->getValue() === array(0 => NULL), 'Name field value contains a NULL value.');
+    $this->assertTrue($entity->name[0]->isEmpty(), format_string('%entity_type: Name item is empty.', array('%entity_type' => $entity_type)));
+    $this->assertTrue($entity->name->isEmpty(), format_string('%entity_type: Name field is empty.', array('%entity_type' => $entity_type)));
+    $this->assertEqual(count($entity->name), 1, format_string('%entity_type: Empty item is considered when counting.', array('%entity_type' => $entity_type)));
+    $this->assertEqual(count(iterator_to_array($entity->name->getIterator())), count($entity->name), format_string('%entity_type: Count matches iterator count.', array('%entity_type' => $entity_type)));
+    $this->assertTrue($entity->name->getValue() === array(0 => NULL), format_string('%entity_type: Name field value contains a NULL value.', array('%entity_type' => $entity_type)));
 
     // Test removing all list items by assigning an empty array.
     $entity->name = array();
-    $this->assertIdentical(count($entity->name), 0, 'Name field contains no items.');
-    $this->assertIdentical($entity->name->getValue(), array(), 'Name field value is an empty array.');
+    $this->assertIdentical(count($entity->name), 0, format_string('%entity_type: Name field contains no items.', array('%entity_type' => $entity_type)));
+    $this->assertIdentical($entity->name->getValue(), array(), format_string('%entity_type: Name field value is an empty array.', array('%entity_type' => $entity_type)));
 
     $entity->name->value = 'foo';
-    $this->assertTrue($entity->name->value, 'foo', 'Name field set.');
+    $this->assertEqual($entity->name->value, 'foo', format_string('%entity_type: Name field set.', array('%entity_type' => $entity_type)));
     // Test removing all list items by setting it to NULL.
     $entity->name = NULL;
-    $this->assertIdentical(count($entity->name), 0, 'Name field contains no items.');
-    $this->assertNull($entity->name->getValue(), 'Name field value is NULL.');
+    $this->assertIdentical(count($entity->name), 0, format_string('%entity_type: Name field contains no items.', array('%entity_type' => $entity_type)));
+    $this->assertNull($entity->name->getValue(), format_string('%entity_type: Name field value is an empty array.', array('%entity_type' => $entity_type)));
 
     // Test get and set field values.
     $entity->name = 'foo';
-    $this->assertEqual($entity->name[0]->getPropertyValues(), array('value' => 'foo'), 'Field value has been retrieved via getPropertyValue()');
+    $this->assertEqual($entity->name[0]->getPropertyValues(), array('value' => 'foo'), format_string('%entity_type: Field value has been retrieved via getPropertyValue()', array('%entity_type' => $entity_type)));
     $entity->name[0]->setPropertyValues(array('value' => 'bar'));
-    $this->assertEqual($entity->name->value, 'bar', 'Field value has been set via setPropertyValue()');
+    $this->assertEqual($entity->name->value, 'bar', format_string('%entity_type: Field value has been set via setPropertyValue()', array('%entity_type' => $entity_type)));
 
     $values = $entity->getPropertyValues();
-    $this->assertEqual($values['name'], array(0 => array('value' => 'bar')), 'Field value has been retrieved via getPropertyValue() from an entity.');
+    $this->assertEqual($values['name'], array(0 => array('value' => 'bar')), format_string('%entity_type: Field value has been retrieved via getPropertyValue() from an entity.', array('%entity_type' => $entity_type)));
     $entity->setPropertyValues(array('name' => 'foo'));
-    $this->assertEqual($entity->name->value, 'foo', 'Field value has been set via setPropertyValue() on an entity.');
+    $this->assertEqual($entity->name->value, 'foo', format_string('%entity_type: Field value has been set via setPropertyValue() on an entity.', array('%entity_type' => $entity_type)));
 
     // Make sure the user id can be set to zero.
     $user_item[0]['value'] = 0;
-    $entity = entity_create('entity_test', array(
+    $entity = entity_create($entity_type, array(
       'name' => $name_item,
       'user_id' => $user_item,
       'field_test_text' => $text_item,
     ));
-    $this->assertNotNull($entity->user_id->value, 'User id is not NULL');
-    $this->assertIdentical($entity->user_id->value, 0, 'User id has been set to 0');
+    $this->assertNotNull($entity->user_id->value, format_string('%entity_type: User id is not NULL', array('%entity_type' => $entity_type)));
+    $this->assertIdentical($entity->user_id->value, 0, format_string('%entity_type: User id has been set to 0', array('%entity_type' => $entity_type)));
 
     // Test setting the ID with the value only.
-    $entity = entity_create('entity_test', array(
+    $entity = entity_create($entity_type, array(
       'name' => $name_item,
       'user_id' => 0,
       'field_test_text' => $text_item,
     ));
-    $this->assertNotNull($entity->user_id->value, 'User id is not NULL');
-    $this->assertIdentical($entity->user_id->value, 0, 'User id has been set to 0');
+    $this->assertNotNull($entity->user_id->value, format_string('%entity_type: User id is not NULL', array('%entity_type' => $entity_type)));
+    $this->assertIdentical($entity->user_id->value, 0, format_string('%entity_type: User id has been set to 0', array('%entity_type' => $entity_type)));
   }
 
   /**
    * Tries to save and load an entity again.
    */
   public function testSave() {
-    $entity = $this->createTestEntity();
+    // All entity variations have to have the same results.
+    foreach (entity_test_entity_types() as $entity_type) {
+      $this->assertSave($entity_type);
+    }
+  }
+
+  /**
+   * Executes the save tests for the given entity type.
+   *
+   * @param string $entity_type
+   *   The entity type to run the tests with.
+   */
+  protected function assertSave($entity_type) {
+    $entity = $this->createTestEntity($entity_type);
     $entity->save();
-    $this->assertTrue((bool) $entity->id(), 'Entity has received an id.');
+    $this->assertTrue((bool) $entity->id(), format_string('%entity_type: Entity has received an id.', array('%entity_type' => $entity_type)));
 
-    $entity = entity_load('entity_test', $entity->id());
-    $this->assertTrue((bool) $entity->id(), 'Entity loaded.');
+    $entity = entity_load($entity_type, $entity->id());
+    $this->assertTrue((bool) $entity->id(), format_string('%entity_type: Entity loaded.', array('%entity_type' => $entity_type)));
 
     // Access the name field.
-    $this->assertEqual(1, $entity->id->value, 'ID value can be read.');
-    $this->assertTrue(is_string($entity->uuid->value), 'UUID value can be read.');
-    $this->assertEqual(LANGUAGE_NOT_SPECIFIED, $entity->langcode->value, 'Language code can be read.');
-    $this->assertEqual(language_load(LANGUAGE_NOT_SPECIFIED), $entity->langcode->language, 'Language object can be read.');
-    $this->assertEqual($this->entity_user->uid, $entity->user_id->value, 'User id can be read.');
-    $this->assertEqual($this->entity_user->name, $entity->user_id->entity->name, 'User name can be read.');
-    $this->assertEqual($this->entity_field_text, $entity->field_test_text->value, 'Text field can be read.');
+    $this->assertEqual(1, $entity->id->value, format_string('%entity_type: ID value can be read.', array('%entity_type' => $entity_type)));
+    $this->assertTrue(is_string($entity->uuid->value), format_string('%entity_type: UUID value can be read.', array('%entity_type' => $entity_type)));
+    $this->assertEqual(LANGUAGE_NOT_SPECIFIED, $entity->langcode->value, format_string('%entity_type: Language code can be read.', array('%entity_type' => $entity_type)));
+    $this->assertEqual(language_load(LANGUAGE_NOT_SPECIFIED), $entity->langcode->language, format_string('%entity_type: Language object can be read.', array('%entity_type' => $entity_type)));
+    $this->assertEqual($this->entity_user->uid, $entity->user_id->value, format_string('%entity_type: User id can be read.', array('%entity_type' => $entity_type)));
+    $this->assertEqual($this->entity_user->name, $entity->user_id->entity->name, format_string('%entity_type: User name can be read.', array('%entity_type' => $entity_type)));
+    $this->assertEqual($this->entity_field_text, $entity->field_test_text->value, format_string('%entity_type: Text field can be read.', array('%entity_type' => $entity_type)));
   }
 
   /**
    * Tests introspection and getting metadata upfront.
    */
   public function testIntrospection() {
+    // All entity variations have to have the same results.
+    foreach (entity_test_entity_types() as $entity_type) {
+      $this->assertIntrospection($entity_type);
+    }
+  }
+
+  /**
+   * Executes the introspection tests for the given entity type.
+   *
+   * @param string $entity_type
+   *   The entity type to run the tests with.
+   */
+  protected function assertIntrospection($entity_type) {
     // Test getting metadata upfront, i.e. without having an entity object.
     $definition = array(
       'type' => 'entity',
       'constraints' => array(
-        'entity type' => 'entity_test',
+        'entity type' => $entity_type,
       ),
       'label' => t('Test entity'),
     );
     $wrapped_entity = typed_data()->create($definition);
     $definitions = $wrapped_entity->getPropertyDefinitions($definition);
-    $this->assertEqual($definitions['name']['type'], 'string_field', 'Name field found.');
-    $this->assertEqual($definitions['user_id']['type'], 'entityreference_field', 'User field found.');
-    $this->assertEqual($definitions['field_test_text']['type'], 'text_field', 'Test-text-field field found.');
+    $this->assertEqual($definitions['name']['type'], 'string_field', $entity_type .': Name field found.');
+    $this->assertEqual($definitions['user_id']['type'], 'entityreference_field', $entity_type .': User field found.');
+    $this->assertEqual($definitions['field_test_text']['type'], 'text_field', $entity_type .': Test-text-field field found.');
 
     // Test introspecting an entity object.
     // @todo: Add bundles and test bundles as well.
-    $entity = entity_create('entity_test', array());
+    $entity = entity_create($entity_type, array());
 
     $definitions = $entity->getPropertyDefinitions();
-    $this->assertEqual($definitions['name']['type'], 'string_field', 'Name field found.');
-    $this->assertEqual($definitions['user_id']['type'], 'entityreference_field', 'User field found.');
-    $this->assertEqual($definitions['field_test_text']['type'], 'text_field', 'Test-text-field field found.');
+    $this->assertEqual($definitions['name']['type'], 'string_field', $entity_type .': Name field found.');
+    $this->assertEqual($definitions['user_id']['type'], 'entityreference_field', $entity_type .': User field found.');
+    $this->assertEqual($definitions['field_test_text']['type'], 'text_field', $entity_type .': Test-text-field field found.');
 
     $name_properties = $entity->name->getPropertyDefinitions();
-    $this->assertEqual($name_properties['value']['type'], 'string', 'String value property of the name found.');
+    $this->assertEqual($name_properties['value']['type'], 'string', $entity_type .': String value property of the name found.');
 
     $userref_properties = $entity->user_id->getPropertyDefinitions();
-    $this->assertEqual($userref_properties['value']['type'], 'integer', 'Entity id property of the user found.');
-    $this->assertEqual($userref_properties['entity']['type'], 'entity', 'Entity reference property of the user found.');
+    $this->assertEqual($userref_properties['value']['type'], 'integer', $entity_type .': Entity id property of the user found.');
+    $this->assertEqual($userref_properties['entity']['type'], 'entity', $entity_type .': Entity reference property of the user found.');
 
     $textfield_properties = $entity->field_test_text->getPropertyDefinitions();
-    $this->assertEqual($textfield_properties['value']['type'], 'string', 'String value property of the test-text field found.');
-    $this->assertEqual($textfield_properties['format']['type'], 'string', 'String format field of the test-text field found.');
-    $this->assertEqual($textfield_properties['processed']['type'], 'string', 'String processed property of the test-text field found.');
+    $this->assertEqual($textfield_properties['value']['type'], 'string', $entity_type .': String value property of the test-text field found.');
+    $this->assertEqual($textfield_properties['format']['type'], 'string', $entity_type .': String format field of the test-text field found.');
+    $this->assertEqual($textfield_properties['processed']['type'], 'string', $entity_type .': String processed property of the test-text field found.');
 
     // @todo: Once the user entity has definitions, continue testing getting
     // them from the $userref_values['entity'] property.
@@ -357,26 +396,39 @@ public function testIntrospection() {
    * Tests iterating over properties.
    */
   public function testIterator() {
-    $entity = $this->createTestEntity();
+    // All entity variations have to have the same results.
+    foreach (entity_test_entity_types() as $entity_type) {
+      $this->assertIterator($entity_type);
+    }
+  }
+
+  /**
+   * Executes the iterator tests for the given entity type.
+   *
+   * @param string $entity_type
+   *   The entity type to run the tests with.
+   */
+  protected function assertIterator($entity_type) {
+    $entity = $this->createTestEntity($entity_type);
 
     foreach ($entity as $name => $field) {
-      $this->assertTrue($field instanceof FieldInterface, "Field $name implements interface.");
+      $this->assertTrue($field instanceof FieldInterface, $entity_type . ": Field $name implements interface.");
 
       foreach ($field as $delta => $item) {
-        $this->assertTrue($field[0] instanceof FieldItemInterface, "Item $delta of field $name implements interface.");
+        $this->assertTrue($field[0] instanceof FieldItemInterface, $entity_type . ": Item $delta of field $name implements interface.");
 
         foreach ($item as $value_name => $value_property) {
-          $this->assertTrue($value_property instanceof TypedDataInterface, "Value $value_name of item $delta of field $name implements interface.");
+          $this->assertTrue($value_property instanceof TypedDataInterface, $entity_type . ": Value $value_name of item $delta of field $name implements interface.");
 
           $value = $value_property->getValue();
-          $this->assertTrue(!isset($value) || is_scalar($value) || $value instanceof EntityInterface, "Value $value_name of item $delta of field $name is a primitive or an entity.");
+          $this->assertTrue(!isset($value) || is_scalar($value) || $value instanceof EntityInterface, $entity_type . ": Value $value_name of item $delta of field $name is a primitive or an entity.");
         }
       }
     }
 
     $properties = $entity->getProperties();
-    $this->assertEqual(array_keys($properties), array_keys($entity->getPropertyDefinitions()), 'All properties returned.');
-    $this->assertEqual($properties, iterator_to_array($entity->getIterator()), 'Entity iterator iterates over all properties.');
+    $this->assertEqual(array_keys($properties), array_keys($entity->getPropertyDefinitions()), format_string('%entity_type: All properties returned.', array('%entity_type' => $entity_type)));
+    $this->assertEqual($properties, iterator_to_array($entity->getIterator()), format_string('%entity_type: Entity iterator iterates over all properties.', array('%entity_type' => $entity_type)));
   }
 
   /**
@@ -384,12 +436,25 @@ public function testIterator() {
    * list interfaces.
    */
   public function testDataStructureInterfaces() {
-    $entity = $this->createTestEntity();
+    // All entity variations have to have the same results.
+    foreach (entity_test_entity_types() as $entity_type) {
+      $this->assertDataStructureInterfaces($entity_type);
+    }
+  }
+
+  /**
+   * Executes the data structure interfaces tests for the given entity type.
+   *
+   * @param string $entity_type
+   *   The entity type to run the tests with.
+   */
+  protected function assertDataStructureInterfaces($entity_type) {
+    $entity = $this->createTestEntity($entity_type);
     $entity->save();
     $entity_definition = array(
       'type' => 'entity',
       'constraints' => array(
-        'entity type' => 'entity_test',
+        'entity type' => $entity_type,
       ),
       'label' => t('Test entity'),
     );
@@ -410,7 +475,7 @@ public function testDataStructureInterfaces() {
       // Field format.
       NULL,
     );
-    $this->assertEqual($strings, $target_strings, 'All contained strings found.');
+    $this->assertEqual($strings, $target_strings, format_string('%entity_type: All contained strings found.', array('%entity_type' => $entity_type)));
   }
 
   /**
@@ -442,21 +507,34 @@ public function getContainedStrings(TypedDataInterface $wrapper, $depth, array &
    * Tests getting processed property values via a computed property.
    */
   public function testComputedProperties() {
+    // All entity variations have to have the same results.
+    foreach (entity_test_entity_types() as $entity_type) {
+      $this->assertComputedProperties($entity_type);
+    }
+  }
+
+  /**
+   * Executes the computed properties tests for the given entity type.
+   *
+   * @param string $entity_type
+   *   The entity type to run the tests with.
+   */
+  protected function assertComputedProperties($entity_type) {
     // Make the test text field processed.
-    $instance = field_info_instance('entity_test', 'field_test_text', 'entity_test');
+    $instance = field_info_instance($entity_type, 'field_test_text', $entity_type);
     $instance['settings']['text_processing'] = 1;
     field_update_instance($instance);
 
-    $entity = $this->createTestEntity();
+    $entity = $this->createTestEntity($entity_type);
     $entity->field_test_text->value = "The <strong>text</strong> text to filter.";
     $entity->field_test_text->format = filter_default_format();
 
     $target = "<p>The &lt;strong&gt;text&lt;/strong&gt; text to filter.</p>\n";
-    $this->assertEqual($entity->field_test_text->processed, $target, 'Text is processed with the default filter.');
+    $this->assertEqual($entity->field_test_text->processed, $target, format_string('%entity_type: Text is processed with the default filter.', array('%entity_type' => $entity_type)));
 
     // Save and load entity and make sure it still works.
     $entity->save();
-    $entity = entity_load('entity_test', $entity->id());
-    $this->assertEqual($entity->field_test_text->processed, $target, 'Text is processed with the default filter.');
+    $entity = entity_load($entity_type, $entity->id());
+    $this->assertEqual($entity->field_test_text->processed, $target, format_string('%entity_type: Text is processed with the default filter.', array('%entity_type' => $entity_type)));
   }
 }
diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityFormTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityFormTest.php
index 278e151ba8e6532c8f16d84c2d149add24c21e07..a9781077bc1fef7a6ce82fe2cc46c7fdffb62c3a 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityFormTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityFormTest.php
@@ -39,6 +39,19 @@ function setUp() {
    * Tests basic form CRUD functionality.
    */
   function testFormCRUD() {
+    // All entity variations have to have the same results.
+    foreach (entity_test_entity_types() as $entity_type) {
+      $this->assertFormCRUD($entity_type);
+    }
+  }
+
+  /**
+   * Executes the form CRUD tests for the given entity type.
+   *
+   * @param string $entity_type
+   *   The entity type to run the tests with.
+   */
+  protected function assertFormCRUD($entity_type) {
     $langcode = LANGUAGE_NOT_SPECIFIED;
     $name1 = $this->randomName(8);
     $name2 = $this->randomName(10);
@@ -49,28 +62,27 @@ function testFormCRUD() {
       "field_test_text[$langcode][0][value]" => $this->randomName(16),
     );
 
-    $this->drupalPost('entity-test/add', $edit, t('Save'));
-    $entity = $this->loadEntityByName($name1);
-    $this->assertTrue($entity, 'Entity found in the database.');
+    $this->drupalPost($entity_type . '/add', $edit, t('Save'));
+    $entity = $this->loadEntityByName($entity_type, $name1);
+    $this->assertTrue($entity, format_string('%entity_type: Entity found in the database.', array('%entity_type' => $entity_type)));
 
     $edit['name'] = $name2;
-    $this->drupalPost('entity-test/manage/' . $entity->id() . '/edit', $edit, t('Save'));
-    $entity = $this->loadEntityByName($name1);
-    $this->assertFalse($entity, 'The entity has been modified.');
-    $entity = $this->loadEntityByName($name2);
-    $this->assertTrue($entity, 'Modified entity found in the database.');
-    $this->assertNotEqual($entity->name->value, $name1, 'The entity name has been modified.');
+    $this->drupalPost($entity_type . '/manage/' . $entity->id() . '/edit', $edit, t('Save'));
+    $entity = $this->loadEntityByName($entity_type, $name1);
+    $this->assertFalse($entity, format_string('%entity_type: The entity has been modified.', array('%entity_type' => $entity_type)));
+    $entity = $this->loadEntityByName($entity_type, $name2);
+    $this->assertTrue($entity, format_string('%entity_type: Modified entity found in the database.', array('%entity_type' => $entity_type)));
+    $this->assertNotEqual($entity->name->value, $name1, format_string('%entity_type: The entity name has been modified.', array('%entity_type' => $entity_type)));
 
-    $this->drupalPost('entity-test/manage/' . $entity->id() . '/edit', array(), t('Delete'));
-    $entity = $this->loadEntityByName($name2);
-    $this->assertFalse($entity, 'Entity not found in the database.');
+    $this->drupalPost($entity_type . '/manage/' . $entity->id() . '/edit', array(), t('Delete'));
+    $entity = $this->loadEntityByName($entity_type, $name2);
+    $this->assertFalse($entity, format_string('%entity_type: Entity not found in the database.', array('%entity_type' => $entity_type)));
   }
 
   /**
    * Loads a test entity by name always resetting the storage controller cache.
    */
-  protected function loadEntityByName($name) {
-    $entity_type = 'entity_test';
+  protected function loadEntityByName($entity_type, $name) {
     // Always load the entity from the database to ensure that changes are
     // correctly picked up.
     entity_get_controller($entity_type)->resetCache();
diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityRevisionsTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityRevisionsTest.php
index 67834944188e3d13694b692bbe41c2d922443cb8..152527bccb4d0a3622b5e7c8a47f131df2cbab17 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityRevisionsTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityRevisionsTest.php
@@ -47,8 +47,22 @@ public function setUp() {
    */
   public function testRevisions() {
 
+    // All revisable entity variations have to have the same results.
+    foreach (entity_test_entity_types(ENTITY_TEST_TYPES_REVISABLE) as $entity_type) {
+      $this->assertRevisions($entity_type);
+    }
+  }
+
+  /**
+   * Executes the revision tests for the given entity type.
+   *
+   * @param string $entity_type
+   *   The entity type to run the tests with.
+   */
+  protected function assertRevisions($entity_type) {
+
     // Create initial entity.
-    $entity = entity_create('entity_test', array(
+    $entity = entity_create($entity_type, array(
       'name' => 'foo',
       'user_id' => $this->web_user->uid,
     ));
@@ -67,7 +81,7 @@ public function testRevisions() {
       $legacy_name = $entity->name->value;
       $legacy_text = $entity->field_test_text->value;
 
-      $entity = entity_test_load($entity->id->value);
+      $entity = entity_load($entity_type, $entity->id->value);
       $entity->setNewRevision(TRUE);
       $names[] = $entity->name->value = $this->randomName(32);
       $texts[] = $entity->field_test_text->value = $this->randomName(32);
@@ -75,25 +89,25 @@ public function testRevisions() {
       $revision_ids[] = $entity->revision_id->value;
 
       // Check that the fields and properties contain new content.
-      $this->assertTrue($entity->revision_id->value > $legacy_revision_id, 'Revision ID changed.');
-      $this->assertNotEqual($entity->name->value, $legacy_name, 'Name changed.');
-      $this->assertNotEqual($entity->field_test_text->value, $legacy_text, 'Text changed.');
+      $this->assertTrue($entity->revision_id->value > $legacy_revision_id, format_string('%entity_type: Revision ID changed.', array('%entity_type' => $entity_type)));
+      $this->assertNotEqual($entity->name->value, $legacy_name, format_string('%entity_type: Name changed.', array('%entity_type' => $entity_type)));
+      $this->assertNotEqual($entity->field_test_text->value, $legacy_text, format_string('%entity_type: Text changed.', array('%entity_type' => $entity_type)));
     }
 
     for ($i = 0; $i < $revision_count; $i++) {
       // Load specific revision.
-      $entity_revision = entity_revision_load('entity_test', $revision_ids[$i]);
+      $entity_revision = entity_revision_load($entity_type, $revision_ids[$i]);
 
       // Check if properties and fields contain the revision specific content.
-      $this->assertEqual($entity_revision->revision_id->value, $revision_ids[$i], 'Revision ID matches.');
-      $this->assertEqual($entity_revision->name->value, $names[$i], 'Name matches.');
-      $this->assertEqual($entity_revision->field_test_text->value, $texts[$i], 'Text matches.');
+      $this->assertEqual($entity_revision->revision_id->value, $revision_ids[$i], format_string('%entity_type: Revision ID matches.', array('%entity_type' => $entity_type)));
+      $this->assertEqual($entity_revision->name->value, $names[$i], format_string('%entity_type: Name matches.', array('%entity_type' => $entity_type)));
+      $this->assertEqual($entity_revision->field_test_text->value, $texts[$i], format_string('%entity_type: Text matches.', array('%entity_type' => $entity_type)));
     }
 
     // Confirm the correct revision text appears in the edit form.
-    $entity = entity_load('entity_test', $entity->id->value);
-    $this->drupalGet('entity-test/manage/' . $entity->id->value);
-    $this->assertFieldById('edit-name', $entity->name->value, 'Name matches in UI.');
-    $this->assertFieldById('edit-field-test-text-und-0-value', $entity->field_test_text->value, 'Text matches in UI.');
+    $entity = entity_load($entity_type, $entity->id->value);
+    $this->drupalGet($entity_type . '/manage/' . $entity->id->value);
+    $this->assertFieldById('edit-name', $entity->name->value, format_string('%entity_type: Name matches in UI.', array('%entity_type' => $entity_type)));
+    $this->assertFieldById('edit-field-test-text-und-0-value', $entity->field_test_text->value, format_string('%entity_type: Text matches in UI.', array('%entity_type' => $entity_type)));
   }
 }
diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityTranslationTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityTranslationTest.php
index 370622d91483cb97bd8aa358437b3ced508aa2d4..b658cd93b722df6ba28c18fa63bec7be284906f8 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityTranslationTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityTranslationTest.php
@@ -50,13 +50,16 @@ function setUp() {
     field_create_field($field);
     $this->field = field_read_field($this->field_name);
 
-    $instance = array(
-      'field_name' => $this->field_name,
-      'entity_type' => 'entity_test',
-      'bundle' => 'entity_test',
-    );
-    field_create_instance($instance);
-    $this->instance = field_read_instance('entity_test', $this->field_name, 'entity_test');
+    // Create instance in all entity variations.
+    foreach (entity_test_entity_types() as $entity_type) {
+      $instance = array(
+        'field_name' => $this->field_name,
+        'entity_type' => $entity_type,
+        'bundle' => $entity_type,
+      );
+      field_create_instance($instance);
+      $this->instance[$entity_type] = field_read_instance($entity_type, $this->field_name, $entity_type);
+    }
 
     // Create test languages.
     $this->langcodes = array();
@@ -73,45 +76,58 @@ function setUp() {
   /**
    * Tests language related methods of the Entity class.
    */
-  function testEntityLanguageMethods() {
-    $entity = entity_create('entity_test', array(
+  public function testEntityLanguageMethods() {
+    // All entity variations have to have the same results.
+    foreach (entity_test_entity_types() as $entity_type) {
+      $this->assertEntityLanguageMethods($entity_type);
+    }
+  }
+
+  /**
+   * Executes the entity language method tests for the given entity type.
+   *
+   * @param string $entity_type
+   *   The entity type to run the tests with.
+   */
+  protected function assertEntityLanguageMethods($entity_type) {
+    $entity = entity_create($entity_type, array(
       'name' => 'test',
       'user_id' => $GLOBALS['user']->uid,
     ));
-    $this->assertEqual($entity->language()->langcode, LANGUAGE_NOT_SPECIFIED, 'Entity language not specified.');
-    $this->assertFalse($entity->getTranslationLanguages(FALSE), 'No translations are available');
+    $this->assertEqual($entity->language()->langcode, LANGUAGE_NOT_SPECIFIED, format_string('%entity_type: Entity language not specified.', array('%entity_type' => $entity_type)));
+    $this->assertFalse($entity->getTranslationLanguages(FALSE), format_string('%entity_type: No translations are available', array('%entity_type' => $entity_type)));
 
     // Set the value in default language.
     $entity->set($this->field_name, array(0 => array('value' => 'default value')));
     // Get the value.
-    $this->assertEqual($entity->getTranslation(LANGUAGE_DEFAULT)->get($this->field_name)->value, 'default value', 'Untranslated value retrieved.');
+    $this->assertEqual($entity->getTranslation(LANGUAGE_DEFAULT)->get($this->field_name)->value, 'default value', format_string('%entity_type: Untranslated value retrieved.', array('%entity_type' => $entity_type)));
 
     // Set the value in a certain language. As the entity is not
     // language-specific it should use the default language and so ignore the
     // specified language.
     $entity->getTranslation($this->langcodes[1])->set($this->field_name, array(0 => array('value' => 'default value2')));
-    $this->assertEqual($entity->get($this->field_name)->value, 'default value2', 'Untranslated value updated.');
-    $this->assertFalse($entity->getTranslationLanguages(FALSE), 'No translations are available');
+    $this->assertEqual($entity->get($this->field_name)->value, 'default value2', format_string('%entity_type: Untranslated value updated.', array('%entity_type' => $entity_type)));
+    $this->assertFalse($entity->getTranslationLanguages(FALSE), format_string('%entity_type: No translations are available', array('%entity_type' => $entity_type)));
 
     // Test getting a field value using a specific language for a not
     // language-specific entity.
-    $this->assertEqual($entity->getTranslation($this->langcodes[1])->get($this->field_name)->value, 'default value2', 'Untranslated value retrieved.');
+    $this->assertEqual($entity->getTranslation($this->langcodes[1])->get($this->field_name)->value, 'default value2', format_string('%entity_type: Untranslated value retrieved.', array('%entity_type' => $entity_type)));
 
     // Now, make the entity language-specific by assigning a language and test
     // translating it.
     $entity->langcode->value = $this->langcodes[0];
     $entity->{$this->field_name} = array();
-    $this->assertEqual($entity->language(), language_load($this->langcodes[0]), 'Entity language retrieved.');
-    $this->assertFalse($entity->getTranslationLanguages(FALSE), 'No translations are available');
+    $this->assertEqual($entity->language(), language_load($this->langcodes[0]), format_string('%entity_type: Entity language retrieved.', array('%entity_type' => $entity_type)));
+    $this->assertFalse($entity->getTranslationLanguages(FALSE), format_string('%entity_type: No translations are available', array('%entity_type' => $entity_type)));
 
     // Set the value in default language.
     $entity->set($this->field_name, array(0 => array('value' => 'default value')));
     // Get the value.
-    $this->assertEqual($entity->get($this->field_name)->value, 'default value', 'Untranslated value retrieved.');
+    $this->assertEqual($entity->get($this->field_name)->value, 'default value', format_string('%entity_type: Untranslated value retrieved.', array('%entity_type' => $entity_type)));
 
     // Set a translation.
     $entity->getTranslation($this->langcodes[1])->set($this->field_name, array(0 => array('value' => 'translation 1')));
-    $this->assertEqual($entity->getTranslation($this->langcodes[1])->{$this->field_name}->value, 'translation 1', 'Translated value set.');
+    $this->assertEqual($entity->getTranslation($this->langcodes[1])->{$this->field_name}->value, 'translation 1', format_string('%entity_type: Translated value set.', array('%entity_type' => $entity_type)));
 
     // Make sure the untranslated value stays.
     $this->assertEqual($entity->get($this->field_name)->value, 'default value', 'Untranslated value stays.');
@@ -120,7 +136,7 @@ function testEntityLanguageMethods() {
     $this->assertEqual($entity->getTranslationLanguages(FALSE), $translations, 'Translations retrieved.');
 
     // Try to get a not available translation.
-    $this->assertNull($entity->getTranslation($this->langcodes[2])->get($this->field_name)->value, 'A translation that is not available is NULL.');
+    $this->assertNull($entity->getTranslation($this->langcodes[2])->get($this->field_name)->value, format_string('%entity_type: A translation that is not available is NULL.', array('%entity_type' => $entity_type)));
 
     // Try to get a value using an invalid language code.
     try {
@@ -135,79 +151,92 @@ function testEntityLanguageMethods() {
     try {
       $field_name = 'field_test_text';
       $value = $entity->getTranslation($this->langcodes[1])->get($field_name);
-      $this->fail('Getting an untranslatable value from a translation in strict mode throws an exception.');
+      $this->fail(format_string('%entity_type: Getting an untranslatable value from a translation in strict mode throws an exception.', array('%entity_type' => $entity_type)));
     }
     catch (InvalidArgumentException $e) {
-      $this->pass('Getting an untranslatable value from a translation in strict mode throws an exception.');
+      $this->pass(format_string('%entity_type: Getting an untranslatable value from a translation in strict mode throws an exception.', array('%entity_type' => $entity_type)));
     }
 
     // Try to get an untranslatable value from a translation in non-strict
     // mode.
     $entity->set($field_name, array(0 => array('value' => 'default value')));
     $value = $entity->getTranslation($this->langcodes[1], FALSE)->get($field_name)->value;
-    $this->assertEqual($value, 'default value', 'Untranslated value retrieved from translation in non-strict mode.');
+    $this->assertEqual($value, 'default value', format_string('%entity_type: Untranslated value retrieved from translation in non-strict mode.', array('%entity_type' => $entity_type)));
 
     // Try to set a value using an invalid language code.
     try {
       $entity->getTranslation('invalid')->set($this->field_name, NULL);
-      $this->fail("Setting a translation for an invalid language throws an exception.");
+      $this->fail(format_string('%entity_type: Setting a translation for an invalid language throws an exception.', array('%entity_type' => $entity_type)));
     }
     catch (InvalidArgumentException $e) {
-      $this->pass("Setting a translation for an invalid language throws an exception.");
+      $this->pass(format_string('%entity_type: Setting a translation for an invalid language throws an exception.', array('%entity_type' => $entity_type)));
     }
 
     // Try to set an untranslatable value into a translation in strict mode.
     try {
       $entity->getTranslation($this->langcodes[1])->set($field_name, NULL);
-      $this->fail("Setting an untranslatable value into a translation in strict mode throws an exception.");
+      $this->fail(format_string('%entity_type: Setting an untranslatable value into a translation in strict mode throws an exception.', array('%entity_type' => $entity_type)));
     }
     catch (InvalidArgumentException $e) {
-      $this->pass("Setting an untranslatable value into a translation in strict mode throws an exception.");
+      $this->pass(format_string('%entity_type: Setting an untranslatable value into a translation in strict mode throws an exception.', array('%entity_type' => $entity_type)));
     }
 
     // Set the value in default language.
     $entity->getTranslation($this->langcodes[1], FALSE)->set($field_name, array(0 => array('value' => 'default value2')));
     // Get the value.
-    $this->assertEqual($entity->get($field_name)->value, 'default value2', 'Untranslated value set into a translation in non-strict mode.');
+    $this->assertEqual($entity->get($field_name)->value, 'default value2', format_string('%entity_type: Untranslated value set into a translation in non-strict mode.', array('%entity_type' => $entity_type)));
   }
 
   /**
    * Tests multilingual properties.
    */
-  function testMultilingualProperties() {
+  public function testMultilingualProperties() {
+    // Test all entity variations with data table support.
+    foreach (entity_test_entity_types(ENTITY_TEST_TYPES_MULTILINGUAL) as $entity_type) {
+      $this->assertMultilingualProperties($entity_type);
+    }
+  }
+
+  /**
+   * Executes the multilingual property tests for the given entity type.
+   *
+   * @param string $entity_type
+   *   The entity type to run the tests with.
+   */
+  protected function assertMultilingualProperties($entity_type) {
     $name = $this->randomName();
     $uid = mt_rand(0, 127);
     $langcode = $this->langcodes[0];
 
     // Create a language neutral entity and check that properties are stored
     // as language neutral.
-    $entity = entity_create('entity_test', array('name' => $name, 'user_id' => $uid));
+    $entity = entity_create($entity_type, array('name' => $name, 'user_id' => $uid));
     $entity->save();
-    $entity = entity_test_load($entity->id());
-    $this->assertEqual($entity->language()->langcode, LANGUAGE_NOT_SPECIFIED, 'Entity created as language neutral.');
-    $this->assertEqual($name, $entity->getTranslation(LANGUAGE_DEFAULT)->get('name')->value, 'The entity name has been correctly stored as language neutral.');
-    $this->assertEqual($uid, $entity->getTranslation(LANGUAGE_DEFAULT)->get('user_id')->value, 'The entity author has been correctly stored as language neutral.');
+    $entity = entity_load($entity_type, $entity->id());
+    $this->assertEqual($entity->language()->langcode, LANGUAGE_NOT_SPECIFIED, format_string('%entity_type: Entity created as language neutral.', array('%entity_type' => $entity_type)));
+    $this->assertEqual($name, $entity->getTranslation(LANGUAGE_DEFAULT)->get('name')->value, format_string('%entity_type: The entity name has been correctly stored as language neutral.', array('%entity_type' => $entity_type)));
+    $this->assertEqual($uid, $entity->getTranslation(LANGUAGE_DEFAULT)->get('user_id')->value, format_string('%entity_type: The entity author has been correctly stored as language neutral.', array('%entity_type' => $entity_type)));
     // As fields, translatable properties should ignore the given langcode and
     // use neutral language if the entity is not translatable.
-    $this->assertEqual($name, $entity->getTranslation($langcode)->get('name')->value, 'The entity name defaults to neutral language.');
-    $this->assertEqual($uid, $entity->getTranslation($langcode)->get('user_id')->value, 'The entity author defaults to neutral language.');
-    $this->assertEqual($name, $entity->get('name')->value, 'The entity name can be retrieved without specifying a language.');
-    $this->assertEqual($uid, $entity->get('user_id')->value, 'The entity author can be retrieved without specifying a language.');
+    $this->assertEqual($name, $entity->getTranslation($langcode)->get('name')->value, format_string('%entity_type: The entity name defaults to neutral language.', array('%entity_type' => $entity_type)));
+    $this->assertEqual($uid, $entity->getTranslation($langcode)->get('user_id')->value, format_string('%entity_type: The entity author defaults to neutral language.', array('%entity_type' => $entity_type)));
+    $this->assertEqual($name, $entity->get('name')->value, format_string('%entity_type: The entity name can be retrieved without specifying a language.', array('%entity_type' => $entity_type)));
+    $this->assertEqual($uid, $entity->get('user_id')->value, format_string('%entity_type: The entity author can be retrieved without specifying a language.', array('%entity_type' => $entity_type)));
 
     // Create a language-aware entity and check that properties are stored
     // as language-aware.
-    $entity = entity_create('entity_test', array('name' => $name, 'user_id' => $uid, 'langcode' => $langcode));
+    $entity = entity_create($entity_type, array('name' => $name, 'user_id' => $uid, 'langcode' => $langcode));
     $entity->save();
-    $entity = entity_test_load($entity->id());
-    $this->assertEqual($entity->language()->langcode, $langcode, 'Entity created as language specific.');
-    $this->assertEqual($name, $entity->getTranslation($langcode)->get('name')->value, 'The entity name has been correctly stored as a language-aware property.');
-    $this->assertEqual($uid, $entity->getTranslation($langcode)->get('user_id')->value, 'The entity author has been correctly stored as a language-aware property.');
+    $entity = entity_load($entity_type, $entity->id());
+    $this->assertEqual($entity->language()->langcode, $langcode, format_string('%entity_type: Entity created as language specific.', array('%entity_type' => $entity_type)));
+    $this->assertEqual($name, $entity->getTranslation($langcode)->get('name')->value, format_string('%entity_type: The entity name has been correctly stored as a language-aware property.', array('%entity_type' => $entity_type)));
+    $this->assertEqual($uid, $entity->getTranslation($langcode)->get('user_id')->value, format_string('%entity_type: The entity author has been correctly stored as a language-aware property.', array('%entity_type' => $entity_type)));
     // Translatable properties on a translatable entity should use default
     // language if LANGUAGE_NOT_SPECIFIED is passed.
-    $this->assertEqual($name, $entity->getTranslation(LANGUAGE_NOT_SPECIFIED)->get('name')->value, 'The entity name defaults to the default language.');
-    $this->assertEqual($uid, $entity->getTranslation(LANGUAGE_NOT_SPECIFIED)->get('user_id')->value, 'The entity author defaults to the default language.');
-    $this->assertEqual($name, $entity->get('name')->value, 'The entity name can be retrieved without specifying a language.');
-    $this->assertEqual($uid, $entity->get('user_id')->value, 'The entity author can be retrieved without specifying a language.');
+    $this->assertEqual($name, $entity->getTranslation(LANGUAGE_NOT_SPECIFIED)->get('name')->value, format_string('%entity_type: The entity name defaults to the default language.', array('%entity_type' => $entity_type)));
+    $this->assertEqual($uid, $entity->getTranslation(LANGUAGE_NOT_SPECIFIED)->get('user_id')->value, format_string('%entity_type: The entity author defaults to the default language.', array('%entity_type' => $entity_type)));
+    $this->assertEqual($name, $entity->get('name')->value, format_string('%entity_type: The entity name can be retrieved without specifying a language.', array('%entity_type' => $entity_type)));
+    $this->assertEqual($uid, $entity->get('user_id')->value, format_string('%entity_type: The entity author can be retrieved without specifying a language.', array('%entity_type' => $entity_type)));
 
     // Create property translations.
     $properties = array();
@@ -230,11 +259,14 @@ function testMultilingualProperties() {
     $entity->save();
 
     // Check that property translation were correctly stored.
-    $entity = entity_test_load($entity->id());
+    $entity = entity_load($entity_type, $entity->id());
     foreach ($this->langcodes as $langcode) {
-      $args = array('%langcode' => $langcode);
-      $this->assertEqual($properties[$langcode]['name'][0], $entity->getTranslation($langcode)->get('name')->value, format_string('The entity name has been correctly stored for language %langcode.', $args));
-      $this->assertEqual($properties[$langcode]['user_id'][0], $entity->getTranslation($langcode)->get('user_id')->value, format_string('The entity author has been correctly stored for language %langcode.', $args));
+      $args = array(
+        '%entity_type' => $entity_type,
+        '%langcode' => $langcode,
+      );
+      $this->assertEqual($properties[$langcode]['name'][0], $entity->getTranslation($langcode)->get('name')->value, format_string('%entity_type: The entity name has been correctly stored for language %langcode.', $args));
+      $this->assertEqual($properties[$langcode]['user_id'][0], $entity->getTranslation($langcode)->get('user_id')->value, format_string('%entity_type: The entity author has been correctly stored for language %langcode.', $args));
     }
 
     // Test query conditions (cache is reset at each call).
@@ -242,34 +274,34 @@ function testMultilingualProperties() {
     // Create an additional entity with only the uid set. The uid for the
     // original language is the same of one used for a translation.
     $langcode = $this->langcodes[1];
-    entity_create('entity_test', array(
+    entity_create($entity_type, array(
       'user_id' => $properties[$langcode]['user_id'],
       'name' => 'some name',
     ))->save();
 
-    $entities = entity_test_load_multiple();
-    $this->assertEqual(count($entities), 3, 'Three entities were created.');
-    $entities = entity_test_load_multiple(array($translated_id));
-    $this->assertEqual(count($entities), 1, 'One entity correctly loaded by id.');
-    $entities = entity_load_multiple_by_properties('entity_test', array('name' => $name));
-    $this->assertEqual(count($entities), 2, 'Two entities correctly loaded by name.');
+    $entities = entity_load_multiple($entity_type);
+    $this->assertEqual(count($entities), 3, format_string('%entity_type: Three entities were created.', array('%entity_type' => $entity_type)));
+    $entities = entity_load_multiple($entity_type, array($translated_id));
+    $this->assertEqual(count($entities), 1, format_string('%entity_type: One entity correctly loaded by id.', array('%entity_type' => $entity_type)));
+    $entities = entity_load_multiple_by_properties($entity_type, array('name' => $name));
+    $this->assertEqual(count($entities), 2, format_string('%entity_type: Two entities correctly loaded by name.', array('%entity_type' => $entity_type)));
     // @todo The default language condition should go away in favor of an
     // explicit parameter.
-    $entities = entity_load_multiple_by_properties('entity_test', array('name' => $properties[$langcode]['name'][0], 'default_langcode' => 0));
-    $this->assertEqual(count($entities), 1, 'One entity correctly loaded by name translation.');
-    $entities = entity_load_multiple_by_properties('entity_test', array('langcode' => $default_langcode, 'name' => $name));
-    $this->assertEqual(count($entities), 1, 'One entity correctly loaded by name and language.');
-
-    $entities = entity_load_multiple_by_properties('entity_test', array('langcode' => $langcode, 'name' => $properties[$langcode]['name'][0]));
-    $this->assertEqual(count($entities), 0, 'No entity loaded by name translation specifying the translation language.');
-    $entities = entity_load_multiple_by_properties('entity_test', array('langcode' => $langcode, 'name' => $properties[$langcode]['name'][0], 'default_langcode' => 0));
-    $this->assertEqual(count($entities), 1, 'One entity loaded by name translation and language specifying to look for translations.');
-    $entities = entity_load_multiple_by_properties('entity_test', array('user_id' => $properties[$langcode]['user_id'][0], 'default_langcode' => NULL));
-    $this->assertEqual(count($entities), 2, 'Two entities loaded by uid without caring about property translatability.');
+    $entities = entity_load_multiple_by_properties($entity_type, array('name' => $properties[$langcode]['name'][0], 'default_langcode' => 0));
+    $this->assertEqual(count($entities), 1, format_string('%entity_type: One entity correctly loaded by name translation.', array('%entity_type' => $entity_type)));
+    $entities = entity_load_multiple_by_properties($entity_type, array('langcode' => $default_langcode, 'name' => $name));
+    $this->assertEqual(count($entities), 1, format_string('%entity_type: One entity correctly loaded by name and language.', array('%entity_type' => $entity_type)));
+
+    $entities = entity_load_multiple_by_properties($entity_type, array('langcode' => $langcode, 'name' => $properties[$langcode]['name'][0]));
+    $this->assertEqual(count($entities), 0, format_string('%entity_type: No entity loaded by name translation specifying the translation language.', array('%entity_type' => $entity_type)));
+    $entities = entity_load_multiple_by_properties($entity_type, array('langcode' => $langcode, 'name' => $properties[$langcode]['name'][0], 'default_langcode' => 0));
+    $this->assertEqual(count($entities), 1, format_string('%entity_type: One entity loaded by name translation and language specifying to look for translations.', array('%entity_type' => $entity_type)));
+    $entities = entity_load_multiple_by_properties($entity_type, array('user_id' => $properties[$langcode]['user_id'][0], 'default_langcode' => NULL));
+    $this->assertEqual(count($entities), 2, format_string('%entity_type: Two entities loaded by uid without caring about property translatability.', array('%entity_type' => $entity_type)));
 
     // Test property conditions and orders with multiple languages in the same
     // query.
-    $query = entity_query('entity_test');
+    $query = entity_query($entity_type);
     $group = $query->andConditionGroup()
       ->condition('user_id', $properties[$default_langcode]['user_id'], '=', $default_langcode)
       ->condition('name', $properties[$default_langcode]['name'], '=', $default_langcode);
@@ -277,14 +309,14 @@ function testMultilingualProperties() {
       ->condition($group)
       ->condition('name', $properties[$langcode]['name'], '=', $langcode)
       ->execute();
-    $this->assertEqual(count($result), 1, 'One entity loaded by name and uid using different language meta conditions.');
+    $this->assertEqual(count($result), 1, format_string('%entity_type: One entity loaded by name and uid using different language meta conditions.', array('%entity_type' => $entity_type)));
 
     // Test mixed property and field conditions.
-    $entity = entity_load('entity_test', reset($result), TRUE);
+    $entity = entity_load($entity_type, reset($result), TRUE);
     $field_value = $this->randomString();
     $entity->getTranslation($langcode)->set($this->field_name, array(array('value' => $field_value)));
     $entity->save();
-    $query = entity_query('entity_test');
+    $query = entity_query($entity_type);
     $default_langcode_group = $query->andConditionGroup()
       ->condition('user_id', $properties[$default_langcode]['user_id'], '=', $default_langcode)
       ->condition('name', $properties[$default_langcode]['name'], '=', $default_langcode);
@@ -296,7 +328,7 @@ function testMultilingualProperties() {
       ->condition($default_langcode_group)
       ->condition($langcode_group)
       ->execute();
-    $this->assertEqual(count($result), 1, 'One entity loaded by name, uid and field value using different language meta conditions.');
+    $this->assertEqual(count($result), 1, format_string('%entity_type: One entity loaded by name, uid and field value using different language meta conditions.', array('%entity_type' => $entity_type)));
   }
 
 }
diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityUUIDTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityUUIDTest.php
index cb2f7f3e0f53f38dd498e5dca20e8e64370b2294..15220cb582e32b9a885399a357bc7284294dfb86 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityUUIDTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityUUIDTest.php
@@ -34,10 +34,23 @@ public static function getInfo() {
    * Tests UUID generation in entity CRUD operations.
    */
   function testCRUD() {
+    // All entity variations have to have the same results.
+    foreach (entity_test_entity_types() as $entity_type) {
+      $this->assertCRUD($entity_type);
+    }
+  }
+
+  /**
+   * Executes the UUID CRUD tests for the given entity type.
+   *
+   * @param string $entity_type
+   *   The entity type to run the tests with.
+   */
+  protected function assertCRUD($entity_type) {
     // Verify that no UUID is auto-generated when passing one for creation.
     $uuid_service = new Uuid();
     $uuid = $uuid_service->generate();
-    $custom_entity = entity_create('entity_test', array(
+    $custom_entity = entity_create($entity_type, array(
       'name' => $this->randomName(),
       'uuid' => $uuid,
     ));
@@ -46,7 +59,7 @@ function testCRUD() {
     $custom_entity->save();
 
     // Verify that a new UUID is generated upon creating an entity.
-    $entity = entity_create('entity_test', array('name' => $this->randomName()));
+    $entity = entity_create($entity_type, array('name' => $this->randomName()));
     $uuid = $entity->uuid();
     $this->assertTrue($uuid);
 
@@ -58,11 +71,11 @@ function testCRUD() {
     $this->assertIdentical($entity->uuid(), $uuid);
 
     // Verify that the UUID is retained upon loading.
-    $entity_loaded = entity_test_load($entity->id(), TRUE);
+    $entity_loaded = entity_load($entity_type, $entity->id(), TRUE);
     $this->assertIdentical($entity_loaded->uuid(), $uuid);
 
     // Verify that entity_load_by_uuid() loads the same entity.
-    $entity_loaded_by_uuid = entity_load_by_uuid('entity_test', $uuid, TRUE);
+    $entity_loaded_by_uuid = entity_load_by_uuid($entity_type, $uuid, TRUE);
     $this->assertIdentical($entity_loaded_by_uuid->uuid(), $uuid);
     $this->assertEqual($entity_loaded_by_uuid->id(), $entity_loaded->id());
 
diff --git a/core/modules/system/lib/Drupal/system/Tests/Serialization/EntitySerializationTest.php b/core/modules/system/lib/Drupal/system/Tests/Serialization/EntitySerializationTest.php
index f34cd9d2069be9d675eb205f163d3d775e5ef6b1..ea3c9603989164d0b98c7a1d290550249f7baaba 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Serialization/EntitySerializationTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Serialization/EntitySerializationTest.php
@@ -59,7 +59,7 @@ protected function setUp() {
         'format' => 'full_html',
       ),
     );
-    $this->entity = entity_create('entity_test', $this->values);
+    $this->entity = entity_create('entity_test_mulrev', $this->values);
     $this->entity->save();
   }
 
@@ -105,7 +105,7 @@ public function testNormalize() {
     foreach (array_keys($expected) as $fieldName) {
       $this->assertEqual($expected[$fieldName], $normalized[$fieldName], "ComplexDataNormalizer produces expected array for $fieldName.");
     }
-    $this->assertEqual(array_keys($expected), array_keys($normalized), 'No unexpected data is added to the normalized array.');
+    $this->assertEqual(array_diff_key($normalized, $expected), array(), 'No unexpected data is added to the normalized array.');
   }
 
   /**
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 617986a1aaf5b02052c87c5e688a25d1ba90897e..dacd1f5e18a18fba02af24b377f084abad106423 100644
--- a/core/modules/system/tests/modules/entity_test/entity_test.install
+++ b/core/modules/system/tests/modules/entity_test/entity_test.install
@@ -18,25 +18,241 @@ function entity_test_install() {
   );
   field_create_field($field);
 
-  $instance = array(
-    'entity_type' => 'entity_test',
-    'field_name' => 'field_test_text',
-    'bundle' => 'entity_test',
-    'label' => 'Test text-field',
-    'widget' => array(
-      'type' => 'text_textfield',
-      'weight' => 0,
-    ),
+  $entity_types = array(
+    'entity_test',
+    'entity_test_rev',
+    'entity_test_mul',
+    'entity_test_mulrev',
   );
-  field_create_instance($instance);
+  foreach ($entity_types as $entity_type) {
+    $instance = array(
+      'entity_type' => $entity_type,
+      'field_name' => 'field_test_text',
+      'bundle' => $entity_type,
+      'label' => 'Test text-field',
+      'widget' => array(
+        'type' => 'text_textfield',
+        'weight' => 0,
+      ),
+    );
+    field_create_instance($instance);
+  }
 }
 
 /**
  * Implements hook_schema().
  */
 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,
+      ),
+      '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,
+      ),
+      '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' => '',
+      ),
+    ),
+    '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', 'id', 'langcode'),
+  );
+
+  // 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,
+      ),
+      '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' => 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_mul' => 'id'),
+    ),
+    'primary key' => array('id', 'langcode'),
+  );
+
+  // 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',
@@ -44,7 +260,7 @@ function entity_test_schema() {
         'description' => 'Primary Key: Unique entity-test item ID.',
       ),
       'revision_id' => array(
-        'description' => 'The current {entity_test_property_revision}.revision_id version identifier.',
+        'description' => 'The current {entity_test_mulrev_property_revision}.revision_id version identifier.',
         'type' => 'int',
         'unsigned' => TRUE,
         'not null' => TRUE,
@@ -69,17 +285,17 @@ function entity_test_schema() {
       'uuid' => array('uuid'),
     ),
   );
-  $schema['entity_test_property_data'] = array(
-    'description' => 'Stores entity_test item properties.',
+  $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}.id of the test entity.',
+        'description' => 'The {entity_test_mulrev}.id of the test entity.',
       ),
       'revision_id' => array(
-        'description' => 'The current {entity_test_property_revision}.revision_id version identifier.',
+        'description' => 'The current {entity_test_mulrev_property_revision}.revision_id version identifier.',
         'type' => 'int',
         'unsigned' => TRUE,
         'not null' => TRUE,
@@ -110,7 +326,7 @@ function entity_test_schema() {
         'unsigned' => TRUE,
         'not null' => FALSE,
         'default' => NULL,
-        'description' => "The {users}.uid of the associated user.",
+        'description' => 'The {users}.uid of the associated user.',
       ),
     ),
     'indexes' => array(
@@ -118,18 +334,18 @@ function entity_test_schema() {
     ),
     'foreign keys' => array(
       'user_id' => array('users' => 'uid'),
-      'id' => array('entity_test' => 'id'),
+      'id' => array('entity_test_mulrev' => 'id'),
     ),
     'primary key' => array('id', 'langcode'),
   );
-  $schema['entity_test_property_revision'] = array(
-    'description' => 'Stores entity_test item property revisions.',
+  $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}.id of the test entity.',
+        'description' => 'The {entity_test_mulrev}.id of the test entity.',
       ),
       'revision_id' => array(
         'type' => 'serial',
@@ -162,7 +378,7 @@ function entity_test_schema() {
         'unsigned' => TRUE,
         'not null' => FALSE,
         'default' => NULL,
-        'description' => "The {users}.uid of the associated user.",
+        'description' => 'The {users}.uid of the associated user.',
       ),
     ),
     'indexes' => array(
@@ -170,9 +386,10 @@ function entity_test_schema() {
     ),
     'foreign keys' => array(
       'user_id' => array('users' => 'uid'),
-      'id' => array('entity_test' => 'id'),
+      'id' => array('entity_test_mulrev' => 'id'),
     ),
     'primary key' => array('revision_id', 'id', 'langcode'),
   );
+
   return $schema;
 }
diff --git a/core/modules/system/tests/modules/entity_test/entity_test.module b/core/modules/system/tests/modules/entity_test/entity_test.module
index 90636149b79e3984c0e346619900ff6d5315a746..2752729cc58114ba87538d2d04c28e0b62a38d18 100644
--- a/core/modules/system/tests/modules/entity_test/entity_test.module
+++ b/core/modules/system/tests/modules/entity_test/entity_test.module
@@ -2,11 +2,54 @@
 
 /**
  * @file
- * Test module for the entity API providing an entity type for testing.
+ * Test module for the entity API providing several entity types for testing.
  */
 
-use Drupal\entity_test\Plugin\Core\Entity\EntityTest;
+use Drupal\Core\Entity\EntityInterface;
 
+/**
+ * Filter that limits test entity list to revisable ones.
+ */
+const ENTITY_TEST_TYPES_REVISABLE = 1;
+
+/**
+ * Filter that limits test entity list to multilingual ones.
+ */
+const ENTITY_TEST_TYPES_MULTILINGUAL = 2;
+
+/**
+ * Returns a list of test entity types.
+ *
+ * The returned entity types are one for each available entity storage type:
+ * - The plain entity_test type supports neither revisions nor multilingual
+ *   properties.
+ * - The entity_test_mul type supports multilingual properties.
+ * - The entity_test_rev type supports revisions.
+ * - The entity_test_mulrev type supports both revisions and multilingual
+ *   properties.
+ *
+ * @param int $filter
+ *   Either ENTITY_TEST_TYPES_REVISABLE to only return revisable entity types or
+ *   ENTITY_TEST_TYPES_MULTILINGUAL to only return multilingual ones. Defaults
+ *   to NULL, which returns all.
+ *
+ * @return array
+ *   List with entity_types.
+ */
+function entity_test_entity_types($filter = NULL) {
+  $types = array();
+  if ($filter == NULL) {
+    $types[] = 'entity_test';
+  }
+  if ($filter != ENTITY_TEST_TYPES_REVISABLE) {
+    $types[] = 'entity_test_mul';
+  }
+  if ($filter != ENTITY_TEST_TYPES_MULTILINGUAL) {
+    $types[] = 'entity_test_rev';
+  }
+  $types[] = 'entity_test_mulrev';
+  return drupal_map_assoc($types);
+}
 
 /**
  * Implements hook_entity_info_alter().
@@ -14,7 +57,9 @@
 function entity_test_entity_info_alter(&$info) {
   // Optionally specify a translation handler for testing translations.
   if (state()->get('entity_test.translation')) {
-    $info['entity_test']['translation']['entity_test'] = TRUE;
+    foreach(entity_test_entity_types() as $entity_type) {
+      $info[$entity_type]['translation'][$entity_type] = TRUE;
+    }
   }
 }
 
@@ -69,55 +114,71 @@ function entity_test_permission() {
 function entity_test_menu() {
   $items = array();
 
-  $items['entity-test/add'] = array(
-    'title' => 'Add an entity_test',
-    'page callback' => 'entity_test_add',
-    'access arguments' => array('administer entity_test content'),
-    'type' => MENU_NORMAL_ITEM,
-  );
-
-  $items['entity-test/manage/%entity_test'] = array(
-    'title' => 'Edit test entity',
-    'page callback' => 'entity_test_edit',
-    'page arguments' => array(2),
-    'access arguments' => array('administer entity_test content'),
-    'type' => MENU_NORMAL_ITEM,
-  );
-
-  $items['entity-test/manage/%entity_test/edit'] = array(
-    'title' => 'Edit',
-    'type' => MENU_DEFAULT_LOCAL_TASK,
-  );
+  foreach(entity_test_entity_types() as $entity_type) {
+    $items[$entity_type . '/add'] = array(
+      'title' => 'Add an @type',
+      'title arguments' => array('@type' => $entity_type),
+      'page callback' => 'entity_test_add',
+      'page arguments' => array($entity_type),
+      'access arguments' => array('administer entity_test content'),
+      'type' => MENU_NORMAL_ITEM,
+    );
+
+    $items[$entity_type . '/manage/%' . $entity_type] = array(
+      'title' => 'Edit @type',
+      'title arguments' => array('@type' => $entity_type),
+      'page callback' => 'entity_test_edit',
+      'page arguments' => array(2),
+      'access arguments' => array('administer entity_test content'),
+      'type' => MENU_NORMAL_ITEM,
+    );
+
+    $items[$entity_type . '/manage/%' . $entity_type . '/edit'] = array(
+      'title' => 'Edit',
+      'type' => MENU_DEFAULT_LOCAL_TASK,
+    );
+  }
 
   return $items;
 }
 
+/**
+ * Implements hook_form_BASE_FORM_ID_alter().
+ */
+function entity_test_form_node_form_alter(&$form, &$form_state, $form_id) {
+  $langcode = $form_state['controller']->getFormLangcode($form_state);
+  variable_set('entity_form_langcode', $langcode);
+}
+
 /**
  * Menu callback: displays the 'Add new entity_test' form.
  *
+ * @param string $entity_type
+ *   Name of the entity type for which a create form should be displayed.
+ *
  * @return array
  *   The processed form for a new entity_test.
  *
  * @see entity_test_menu()
  */
-function entity_test_add() {
-  drupal_set_title(t('Create an entity_test'));
-  $entity = entity_create('entity_test', array());
+function entity_test_add($entity_type) {
+  drupal_set_title(t('Create an @type', array('@type' => $entity_type)));
+  $entity = entity_create($entity_type, array());
   return entity_get_form($entity);
 }
 
 /**
  * Menu callback: displays the 'Edit existing entity_test' form.
  *
- * @param array $entity
+ * @param \Drupal\Core\Entity\EntityInterface $entity
  *   The entity to be edited.
  *
  * @return array
- *   The processed form for the edited entity_test.
+ *   The processed form for the edited entity.
  *
  * @see entity_test_menu()
  */
-function entity_test_edit(EntityTest $entity) {
+function entity_test_edit(EntityInterface $entity) {
   drupal_set_title($entity->label(), PASS_THROUGH);
   return entity_get_form($entity);
 }
@@ -130,7 +191,7 @@ function entity_test_edit(EntityTest $entity) {
  * @param bool $reset
  *   A boolean indicating that the internal cache should be reset.
  *
- * @return Drupal\entity_test\Plugin\Core\Entity\EntityTest
+ * @return \Drupal\entity_test\Plugin\Core\Entity\EntityTest
  *   The loaded entity object, or FALSE if the entity cannot be loaded.
  */
 function entity_test_load($id, $reset = FALSE) {
@@ -138,36 +199,48 @@ function entity_test_load($id, $reset = FALSE) {
 }
 
 /**
- * Loads multiple test entities based on certain conditions.
+ * Loads a test entity.
  *
- * @param array $ids
- *   (optional) An array of entity IDs. If omitted, all entities are loaded.
+ * @param int $id
+ *   A test entity ID.
  * @param bool $reset
  *   A boolean indicating that the internal cache should be reset.
  *
- * @return array
- *   An array of test entity objects, indexed by ID.
+ * @return \Drupal\entity_test\Plugin\Core\Entity\EntityTestRev
+ *   The loaded entity object, or FALSE if the entity cannot be loaded.
  */
-function entity_test_load_multiple(array $ids = NULL, $reset = FALSE) {
-  return entity_load_multiple('entity_test', $ids, $reset);
+function entity_test_rev_load($id, $reset = FALSE) {
+  return entity_load('entity_test_rev', $id, $reset);
 }
 
 /**
- * Deletes multiple test entities.
+ * Loads a test entity.
+ *
+ * @param int $id
+ *   A test entity ID.
+ * @param bool $reset
+ *   A boolean indicating that the internal cache should be reset.
  *
- * @param $ids
- *   An array of test entity IDs.
+ * @return \Drupal\entity_test\Plugin\Core\Entity\EntityTestMul
+ *   The loaded entity object, or FALSE if the entity cannot be loaded.
  */
-function entity_test_delete_multiple(array $ids) {
-  entity_delete_multiple('entity_test', $ids);
+function entity_test_mul_load($id, $reset = FALSE) {
+  return entity_load('entity_test_mul', $id, $reset);
 }
 
 /**
- * Implements hook_form_BASE_FORM_ID_alter().
+ * Loads a test entity.
+ *
+ * @param int $id
+ *   A test entity ID.
+ * @param bool $reset
+ *   A boolean indicating that the internal cache should be reset.
+ *
+ * @return \Drupal\entity_test\Plugin\Core\Entity\EntityTestMulRev
+ *   The loaded entity object, or FALSE if the entity cannot be loaded.
  */
-function entity_test_form_node_form_alter(&$form, &$form_state, $form_id) {
-  $langcode = $form_state['controller']->getFormLangcode($form_state);
-  variable_set('entity_form_langcode', $langcode);
+function entity_test_mulrev_load($id, $reset = FALSE) {
+  return entity_load('entity_test_mulrev', $id, $reset);
 }
 
 /**
diff --git a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestFormController.php b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestFormController.php
index a65f06fb78d4f2d2ade305ccf6ed4a13a4c008f5..e1892a0fbdf6026f7257f462fe57803e743bc527 100644
--- a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestFormController.php
+++ b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestFormController.php
@@ -61,11 +61,16 @@ public function save(array $form, array &$form_state) {
     $is_new = $entity->isNew();
     $entity->save();
 
-    $message = $is_new ? t('entity_test @id has been created.', array('@id' => $entity->id())) : t('entity_test @id has been updated.', array('@id' => $entity->id()));
+    if ($is_new) {
+     $message = t('%entity_type @id has been created.', array('@id' => $entity->id(), '%entity_type' => $entity->entityType()));
+    }
+    else {
+      $message = t('%entity_type @id has been updated.', array('@id' => $entity->id(), '%entity_type' => $entity->entityType()));
+    }
     drupal_set_message($message);
 
     if ($entity->id()) {
-      $form_state['redirect'] = 'entity-test/manage/' . $entity->id() . '/edit';
+      $form_state['redirect'] = $entity->entityType() . '/manage/' . $entity->id() . '/edit';
     }
     else {
       // Error on save.
@@ -80,7 +85,7 @@ public function save(array $form, array &$form_state) {
   public function delete(array $form, array &$form_state) {
     $entity = $this->getEntity($form_state);
     $entity->delete();
-    drupal_set_message(t('entity_test @id has been deleted.', array('@id' => $entity->id())));
+    drupal_set_message(t('%entity_type @id has been deleted.', array('@id' => $entity->id(), '%entity_type' => $entity->entityType())));
     $form_state['redirect'] = '<front>';
   }
 }
diff --git a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestMulRevStorageController.php b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestMulRevStorageController.php
new file mode 100644
index 0000000000000000000000000000000000000000..f940ed0ce105acebe178dab36562814675daaf61
--- /dev/null
+++ b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestMulRevStorageController.php
@@ -0,0 +1,39 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\entity_test\EntityTestMulRevStorageController.
+ */
+
+namespace Drupal\entity_test;
+
+use Drupal\entity_test\EntityTestStorageController;
+
+/**
+ * Defines the controller class for the test entity.
+ *
+ * This extends the Drupal\entity_test\EntityTestStorageController class, adding
+ * required special handling for test entities with multilingual property and
+ * revision support.
+ */
+class EntityTestMulRevStorageController extends EntityTestStorageController {
+
+  /**
+   * Overrides \Drupal\entity_test\EntityTestStorageController::baseFieldDefinitions().
+   */
+  public function baseFieldDefinitions() {
+    $fields = parent::baseFieldDefinitions();
+    $fields['revision_id'] = array(
+      'label' => t('ID'),
+      'description' => t('The version id of the test entity.'),
+      'type' => 'integer_field',
+      'read-only' => TRUE,
+    );
+    $fields['default_langcode'] = array(
+      'label' => t('Default language'),
+      'description' => t('Flag to inditcate whether this is the default language.'),
+      'type' => 'boolean_field',
+    );
+    return $fields;
+  }
+}
diff --git a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestMulStorageController.php b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestMulStorageController.php
new file mode 100644
index 0000000000000000000000000000000000000000..28a90eee6a2fadbad9098eb25950ccc37cfbebdb
--- /dev/null
+++ b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestMulStorageController.php
@@ -0,0 +1,33 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\entity_test\EntityTestMulStorageController.
+ */
+
+namespace Drupal\entity_test;
+
+use Drupal\entity_test\EntityTestStorageController;
+
+/**
+ * Defines the controller class for the test entity.
+ *
+ * This extends the Drupal\entity_test\EntityTestStorageController class, adding
+ * required special handling for test entities with multilingual property
+ * support.
+ */
+class EntityTestMulStorageController extends EntityTestStorageController {
+
+  /**
+   * Overrides \Drupal\entity_test\EntityTestStorageController::baseFieldDefinitions().
+   */
+  public function baseFieldDefinitions() {
+    $fields = parent::baseFieldDefinitions();
+    $fields['default_langcode'] = array(
+      'label' => t('Default language'),
+      'description' => t('Flag to inditcate whether this is the default language.'),
+      'type' => 'boolean_field',
+    );
+    return $fields;
+  }
+}
diff --git a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestRevStorageController.php b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestRevStorageController.php
new file mode 100644
index 0000000000000000000000000000000000000000..0fec01ebfc369d6cba6335cd164e423b33ee079a
--- /dev/null
+++ b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestRevStorageController.php
@@ -0,0 +1,33 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\entity_test\EntityTestRevStorageController.
+ */
+
+namespace Drupal\entity_test;
+
+use Drupal\entity_test\EntityTestStorageController;
+
+/**
+ * Defines the controller class for the test entity.
+ *
+ * This extends the Drupal\entity_test\EntityTestStorageController class, adding
+ * required special handling for test entities with revision support.
+ */
+class EntityTestRevStorageController extends EntityTestStorageController {
+
+  /**
+   * Overrides \Drupal\entity_test\EntityTestStorageController::baseFieldDefinitions().
+   */
+  public function baseFieldDefinitions() {
+    $fields = parent::baseFieldDefinitions();
+    $fields['revision_id'] = array(
+      'label' => t('ID'),
+      'description' => t('The version id of the test entity.'),
+      'type' => 'integer_field',
+      'read-only' => TRUE,
+    );
+    return $fields;
+  }
+}
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 d24ade85f9e367107d688ad416a6411b491a439a..090870069a7224c59ab98a680cf7923a443bf0c2 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,9 +7,6 @@
 
 namespace Drupal\entity_test;
 
-use PDO;
-use Drupal\Core\Entity\Query\QueryInterface;
-use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Entity\DatabaseStorageControllerNG;
 
 /**
@@ -20,123 +17,6 @@
  */
 class EntityTestStorageController extends DatabaseStorageControllerNG {
 
-  /**
-   * Overrides Drupal\Core\Entity\DatabaseStorageController::buildPropertyQuery().
-   */
-  protected function buildPropertyQuery(QueryInterface $entity_query, array $values) {
-    // @todo We should not be using a condition to specify whether conditions
-    // apply to the default language or not. We need to move this to a
-    // separate parameter during the following API refactoring.
-    // 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 esplicitly 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);
-  }
-
-  /**
-   * Maps from storage records to entity objects.
-   *
-   * @return array
-   *   An array of entity objects implementing the EntityInterface.
-   */
-  protected function mapFromStorageRecords(array $records, $load_revision = FALSE) {
-    $property_values = $this->getPropertyValues($records, $load_revision);
-
-    foreach ($records as $id => $record) {
-      $values = isset($property_values[$id]) ? $property_values[$id] : array();
-
-      foreach ($record as $name => $value) {
-        $values[$name][LANGUAGE_DEFAULT][0]['value'] = $value;
-      }
-      $entity = new $this->entityClass($values, $this->entityType);
-      $records[$id] = $entity;
-    }
-    return $records;
-  }
-
-  /**
-   * Attaches property data in all languages for translatable properties.
-   */
-  protected function getPropertyValues($records, $load_revision = FALSE) {
-    $query = db_select('entity_test_property_data', 'data', array('fetch' => PDO::FETCH_ASSOC))
-      ->fields('data')
-      ->condition('id', array_keys($records))
-      ->orderBy('data.id');
-    if ($load_revision) {
-      // Get revision id's.
-      $revision_ids = array();
-      foreach ($records as $record) {
-        $revision_ids[] = $record->revision_id;
-      }
-      $query->condition('revision_id', $revision_ids);
-    }
-    $data = $query->execute();
-    $property_values = array();
-
-    foreach ($data as $values) {
-      $id = $values['id'];
-      // Field values in default language are stored with
-      // LANGUAGE_DEFAULT as key.
-      $langcode = empty($values['default_langcode']) ? $values['langcode'] : LANGUAGE_DEFAULT;
-
-      $property_values[$id]['name'][$langcode][0]['value'] = $values['name'];
-      $property_values[$id]['user_id'][$langcode][0]['value'] = $values['user_id'];
-    }
-    return $property_values;
-  }
-
-  /**
-   * Overrides Drupal\Core\Entity\DatabaseStorageController::postSave().
-   *
-   * Stores values of translatable properties.
-   */
-  protected function postSave(EntityInterface $entity, $update) {
-    $default_langcode = $entity->language()->langcode;
-
-    // Delete and insert to handle removed values.
-    db_delete('entity_test_property_data')
-      ->condition('id', $entity->id())
-      ->execute();
-
-    $query = db_insert('entity_test_property_data');
-
-    foreach ($entity->getTranslationLanguages() as $langcode => $language) {
-      $translation = $entity->getTranslation($langcode);
-
-      $values = array(
-        'id' => $entity->id(),
-        'revision_id' => $entity->getRevisionId(),
-        'langcode' => $langcode,
-        'default_langcode' => intval($default_langcode == $langcode),
-        'name' => $translation->name->value,
-        'user_id' => $translation->user_id->value,
-      );
-
-      $query
-        ->fields(array_keys($values))
-        ->values($values);
-    }
-
-    $query->execute();
-  }
-
-  /**
-   * Overrides Drupal\Core\Entity\DatabaseStorageController::postDelete().
-   */
-  protected function postDelete($entities) {
-    db_delete('entity_test_property_data')
-      ->condition('id', array_keys($entities))
-      ->execute();
-  }
-
   /**
    * Implements \Drupal\Core\Entity\DataBaseStorageControllerNG::baseFieldDefinitions().
    */
@@ -147,12 +27,6 @@ public function baseFieldDefinitions() {
       'type' => 'integer_field',
       'read-only' => TRUE,
     );
-    $fields['revision_id'] = array(
-      'label' => t('ID'),
-      'description' => t('The version id of the test entity.'),
-      'type' => 'integer_field',
-      'read-only' => TRUE,
-    );
     $fields['uuid'] = array(
       'label' => t('UUID'),
       'description' => t('The UUID of the test entity.'),
@@ -163,11 +37,6 @@ public function baseFieldDefinitions() {
       'description' => t('The language code of the test entity.'),
       'type' => 'language_field',
     );
-    $fields['default_langcode'] = array(
-      'label' => t('Default language'),
-      'description' => t('Flag to inditcate whether this is the default language.'),
-      'type' => 'boolean_field',
-    );
     $fields['name'] = array(
       'label' => t('Name'),
       'description' => t('The name of the test entity.'),
diff --git a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Core/Entity/EntityTest.php b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Core/Entity/EntityTest.php
index 22ac2ec762c3555d8ea5fb6ba021592da7b8d357..1c8979ee5b91b3ac0547139059093acd83e39323 100644
--- a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Core/Entity/EntityTest.php
+++ b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Core/Entity/EntityTest.php
@@ -25,13 +25,10 @@
  *   },
  *   translation_controller_class = "Drupal\translation_entity\EntityTranslationControllerNG",
  *   base_table = "entity_test",
- *   data_table = "entity_test_property_data",
- *   revision_table = "entity_test_property_revision",
  *   fieldable = TRUE,
  *   entity_keys = {
  *     "id" = "id",
  *     "uuid" = "uuid",
- *     "revision" = "revision_id"
  *   },
  *   menu_base_path = "entity-test/manage/%entity_test"
  * )
@@ -52,13 +49,6 @@ class EntityTest extends EntityNG {
    */
   public $uuid;
 
-  /**
-   * The entity revision id.
-   *
-   * @var \Drupal\Core\Entity\Field\FieldInterface
-   */
-  public $revision_id;
-
   /**
    * The name of the test entity.
    *
@@ -81,7 +71,6 @@ protected function init() {
     // We unset all defined properties, so magic getters apply.
     unset($this->id);
     unset($this->uuid);
-    unset($this->revision_id);
     unset($this->name);
     unset($this->user_id);
   }
@@ -92,11 +81,4 @@ protected function init() {
   public function label($langcode = LANGUAGE_DEFAULT) {
     return $this->getTranslation($langcode)->name->value;
   }
-
-  /**
-   * Implements Drupal\Core\Entity\EntityInterface::getRevisionId().
-   */
-  public function getRevisionId() {
-    return $this->get('revision_id')->value;
-  }
 }
diff --git a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Core/Entity/EntityTestMul.php b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Core/Entity/EntityTestMul.php
new file mode 100644
index 0000000000000000000000000000000000000000..ec3119c45a12f156440fba7386f79d97b697df4a
--- /dev/null
+++ b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Core/Entity/EntityTestMul.php
@@ -0,0 +1,39 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\entity_test\Plugin\Core\Entity\EntityTestMul.
+ */
+
+namespace Drupal\entity_test\Plugin\Core\Entity;
+
+use Drupal\entity_test\Plugin\Core\Entity\EntityTest;
+use Drupal\Core\Annotation\Plugin;
+use Drupal\Core\Annotation\Translation;
+
+/**
+ * Defines the test entity class.
+ *
+ * @Plugin(
+ *   id = "entity_test_mul",
+ *   label = @Translation("Test entity - data table"),
+ *   module = "entity_test",
+ *   controller_class = "Drupal\entity_test\EntityTestMulStorageController",
+ *   access_controller_class = "Drupal\entity_test\EntityTestAccessController",
+ *   form_controller_class = {
+ *     "default" = "Drupal\entity_test\EntityTestFormController"
+ *   },
+ *   translation_controller_class = "Drupal\translation_entity\EntityTranslationControllerNG",
+ *   base_table = "entity_test_mul",
+ *   data_table = "entity_test_mul_property_data",
+ *   fieldable = TRUE,
+ *   entity_keys = {
+ *     "id" = "id",
+ *     "uuid" = "uuid",
+ *   },
+ *   menu_base_path = "entity_test_mul/manage/%entity_test_mul"
+ * )
+ */
+class EntityTestMul extends EntityTest {
+
+}
diff --git a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Core/Entity/EntityTestMulRev.php b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Core/Entity/EntityTestMulRev.php
new file mode 100644
index 0000000000000000000000000000000000000000..714486a1eac61269534690b46a959ce114321918
--- /dev/null
+++ b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Core/Entity/EntityTestMulRev.php
@@ -0,0 +1,41 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\entity_test\Plugin\Core\Entity\EntityTestMulRev.
+ */
+
+namespace Drupal\entity_test\Plugin\Core\Entity;
+
+use Drupal\entity_test\Plugin\Core\Entity\EntityTestRev;
+use Drupal\Core\Annotation\Plugin;
+use Drupal\Core\Annotation\Translation;
+
+/**
+ * Defines the test entity class.
+ *
+ * @Plugin(
+ *   id = "entity_test_mulrev",
+ *   label = @Translation("Test entity - revisions and data table"),
+ *   module = "entity_test",
+ *   controller_class = "Drupal\entity_test\EntityTestMulRevStorageController",
+ *   access_controller_class = "Drupal\entity_test\EntityTestAccessController",
+ *   form_controller_class = {
+ *     "default" = "Drupal\entity_test\EntityTestFormController"
+ *   },
+ *   translation_controller_class = "Drupal\translation_entity\EntityTranslationControllerNG",
+ *   base_table = "entity_test_mulrev",
+ *   data_table = "entity_test_mulrev_property_data",
+ *   revision_table = "entity_test_mulrev_property_revision",
+ *   fieldable = TRUE,
+ *   entity_keys = {
+ *     "id" = "id",
+ *     "uuid" = "uuid",
+ *     "revision" = "revision_id",
+ *   },
+ *   menu_base_path = "entity_test_mulrev/manage/%entity_test_mulrev"
+ * )
+ */
+class EntityTestMulRev extends EntityTestRev {
+
+}
diff --git a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Core/Entity/EntityTestRev.php b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Core/Entity/EntityTestRev.php
new file mode 100644
index 0000000000000000000000000000000000000000..485b31d4ebe5403caf70dd7d35d33748fdd12301
--- /dev/null
+++ b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Core/Entity/EntityTestRev.php
@@ -0,0 +1,61 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\entity_test\Plugin\Core\Entity\EntityTestRev.
+ */
+
+namespace Drupal\entity_test\Plugin\Core\Entity;
+
+use Drupal\entity_test\Plugin\Core\Entity\EntityTest;
+use Drupal\Core\Annotation\Plugin;
+use Drupal\Core\Annotation\Translation;
+
+/**
+ * Defines the test entity class.
+ *
+ * @Plugin(
+ *   id = "entity_test_rev",
+ *   label = @Translation("Test entity - revisions"),
+ *   module = "entity_test",
+ *   controller_class = "Drupal\entity_test\EntityTestRevStorageController",
+ *   access_controller_class = "Drupal\entity_test\EntityTestAccessController",
+ *   form_controller_class = {
+ *     "default" = "Drupal\entity_test\EntityTestFormController"
+ *   },
+ *   translation_controller_class = "Drupal\translation_entity\EntityTranslationControllerNG",
+ *   base_table = "entity_test_rev",
+ *   revision_table = "entity_test_rev_revision",
+ *   fieldable = TRUE,
+ *   entity_keys = {
+ *     "id" = "id",
+ *     "uuid" = "uuid",
+ *     "revision" = "revision_id",
+ *   },
+ *   menu_base_path = "entity_test_rev/manage/%entity_test_rev"
+ * )
+ */
+class EntityTestRev extends EntityTest {
+
+  /**
+   * The entity revision id.
+   *
+   * @var \Drupal\Core\Entity\Field\FieldInterface
+   */
+  public $revision_id;
+
+  /**
+   * Overrides EntityNG::init().
+   */
+  public function init() {
+    parent::init();
+    unset($this->revision_id);
+  }
+
+  /**
+   * Implements Drupal\Core\Entity\EntityInterface::getRevisionId().
+   */
+  public function getRevisionId() {
+    return $this->get('revision_id')->value;
+  }
+}
diff --git a/core/modules/translation_entity/lib/Drupal/translation_entity/Tests/EntityTestTranslationUITest.php b/core/modules/translation_entity/lib/Drupal/translation_entity/Tests/EntityTestTranslationUITest.php
index f66fcc3ba57a88ebe17464fb2921ef51bd8ad195..2fbb509370b9c2c8036f09c07c8df2b6cd85e8a8 100644
--- a/core/modules/translation_entity/lib/Drupal/translation_entity/Tests/EntityTestTranslationUITest.php
+++ b/core/modules/translation_entity/lib/Drupal/translation_entity/Tests/EntityTestTranslationUITest.php
@@ -31,7 +31,8 @@ public static function getInfo() {
    * Overrides \Drupal\simpletest\WebTestBase::setUp().
    */
   function setUp() {
-    $this->entityType = 'entity_test';
+    // Use the entity_test_mul as this has multilingual property support.
+    $this->entityType = 'entity_test_mul';
     parent::setUp();
   }
 
diff --git a/core/modules/translation_entity/lib/Drupal/translation_entity/Tests/EntityTranslationUITest.php b/core/modules/translation_entity/lib/Drupal/translation_entity/Tests/EntityTranslationUITest.php
index 6ad80a3cee8c9ea4548a929ed9e2d43a7e072299..42be87c61cdb8a1c0dce5fee8d5b0fe75165b127 100644
--- a/core/modules/translation_entity/lib/Drupal/translation_entity/Tests/EntityTranslationUITest.php
+++ b/core/modules/translation_entity/lib/Drupal/translation_entity/Tests/EntityTranslationUITest.php
@@ -220,8 +220,10 @@ function testTranslationUI() {
     $this->drupalPost($path, array(), t('Delete translation'));
     $this->drupalPost(NULL, array(), t('Delete'));
     $entity = entity_load($this->entityType, $entity->id(), TRUE);
-    $translations = $entity->getTranslationLanguages();
-    $this->assertTrue(count($translations) == 2 && empty($translations[$enabled_langcode]), 'Translation successfully deleted.');
+    if ($this->assertTrue(is_object($entity), 'Entity found')) {
+      $translations = $entity->getTranslationLanguages();
+      $this->assertTrue(count($translations) == 2 && empty($translations[$enabled_langcode]), 'Translation successfully deleted.');
+    }
   }
 
   /**