diff --git a/core/lib/Drupal/Core/Entity/DatabaseStorageController.php b/core/lib/Drupal/Core/Entity/DatabaseStorageController.php
index 1c7d9fd..2ca1ff3 100644
--- a/core/lib/Drupal/Core/Entity/DatabaseStorageController.php
+++ b/core/lib/Drupal/Core/Entity/DatabaseStorageController.php
@@ -263,7 +263,7 @@ public function loadRevision($revision_id) {
     // which attaches fields (if supported by the entity type) and calls the
     // entity type specific load callback, for example hook_node_load().
     if (!empty($queried_entities)) {
-      $this->attachLoad($queried_entities, TRUE);
+      $this->attachLoad($queried_entities, $revision_id);
     }
     return reset($queried_entities);
   }
diff --git a/core/lib/Drupal/Core/Entity/DatabaseStorageControllerNG.php b/core/lib/Drupal/Core/Entity/DatabaseStorageControllerNG.php
index e18edbd..67c3ce2 100644
--- a/core/lib/Drupal/Core/Entity/DatabaseStorageControllerNG.php
+++ b/core/lib/Drupal/Core/Entity/DatabaseStorageControllerNG.php
@@ -148,6 +148,56 @@ protected function buildPropertyQuery(QueryInterface $entity_query, array $value
   }
 
   /**
+   * Overrides \Drupal\Core\Entity\DatabaseStorageController::buildQuery().
+   */
+  protected function buildQuery($ids, $revision_id = FALSE) {
+    $query = db_select($this->entityInfo['base_table'], 'base');
+
+    $query->addTag($this->entityType . '_load_multiple');
+
+    if (!$this->dataTable) {
+      if ($revision_id) {
+        $query->join($this->revisionTable, 'revision', "revision.{$this->idKey} = base.{$this->idKey} AND revision.{$this->revisionKey} = :revisionId", array(':revisionId' => $revision_id));
+      }
+      elseif ($this->revisionKey) {
+        $query->join($this->revisionTable, 'revision', "revision.{$this->revisionKey} = base.{$this->revisionKey}");
+      }
+    }
+
+    // Add fields from the {entity} table.
+    $entity_fields = $this->entityInfo['schema_fields_sql']['base_table'];
+
+    if ($this->revisionKey && !$this->dataTable) {
+      // Add all fields from the {entity_revision} table.
+      $entity_revision_fields = drupal_map_assoc($this->entityInfo['schema_fields_sql']['revision_table']);
+      // The id field is provided by entity, so remove it.
+      unset($entity_revision_fields[$this->idKey]);
+
+      // Remove all fields from the base table that are also fields by the same
+      // name in the revision table.
+      $entity_field_keys = array_flip($entity_fields);
+      foreach ($entity_revision_fields as $key => $name) {
+        if (isset($entity_field_keys[$name])) {
+          unset($entity_fields[$entity_field_keys[$name]]);
+        }
+      }
+      $query->fields('revision', $entity_revision_fields);
+
+      // Compare revision id of the base and revision table, if equal then this
+      // is the default revision.
+      $query->addExpression('base.' . $this->revisionKey . ' = revision.' . $this->revisionKey, 'isDefaultRevision');
+    }
+
+    $query->fields('base', $entity_fields);
+
+    if ($ids) {
+      $query->condition("base.{$this->idKey}", $ids, 'IN');
+    }
+
+    return $query;
+  }
+
+  /**
    * Overrides DatabaseStorageController::attachLoad().
    *
    * Added mapping from storage records to entities.
@@ -220,39 +270,54 @@ protected function mapFromStorageRecords(array $records, $load_revision = FALSE)
    *
    * @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.
+   * @param int $revision_id
+   *   (optional) The revision to be loaded. Defaults to FALSE.
    */
-  protected function attachPropertyData(array &$entities, $load_revision = FALSE) {
+  protected function attachPropertyData(array &$entities, $revision_id = FALSE) {
     if ($this->dataTable) {
-      $query = db_select($this->dataTable, 'data', array('fetch' => PDO::FETCH_ASSOC))
+      // If a revision table is available, we need all the properties of the
+      // latest revision. Otherwise we fall back to the data table.
+      $table = $this->revisionTable ?: $this->dataTable;
+      $query = db_select($table, '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;
+
+      if ($this->revisionTable) {
+        if ($revision_id) {
+          $query->condition($this->revisionKey, $revision_id);
+        }
+        else {
+          // 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);
         }
-        $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];
+
+        if ($this->revisionTable) {
+          // Unless a revision id was specified we are dealing with the default
+          // revision.
+          $entities[$id]->getBCEntity()->isDefaultRevision = intval(empty($revision_id));
+        }
+
         // 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'])) {
+          if (isset($data_fields[$name])) {
             // @todo Figure out how to determine which property has to be set.
             // Currently it's guessing, and guessing is evil!
             $property_definition = $translation->{$name}->getPropertyDefinitions();
@@ -483,7 +548,9 @@ protected function mapToDataStorageRecord(EntityInterface $entity, $langcode) {
 
     $record = new \stdClass();
     foreach ($this->entityInfo['schema_fields_sql']['data_table'] as $name) {
-      $record->$name = $translation->$name->value;
+      if (isset($translation->$name->value)) {
+        $record->$name = $translation->$name->value;
+      }
     }
     $record->langcode = $langcode;
     $record->default_langcode = intval($default_langcode == $langcode);
diff --git a/core/modules/node/lib/Drupal/node/NodeStorageController.php b/core/modules/node/lib/Drupal/node/NodeStorageController.php
index c9e832e..aefc0d2 100644
--- a/core/modules/node/lib/Drupal/node/NodeStorageController.php
+++ b/core/modules/node/lib/Drupal/node/NodeStorageController.php
@@ -80,21 +80,6 @@ protected function attachLoad(&$queried_entities, $load_revision = FALSE) {
   }
 
   /**
-   * Overrides Drupal\Core\Entity\DatabaseStorageController::buildQuery().
-   */
-  protected function buildQuery($ids, $revision_id = FALSE) {
-    // Ensure that uid is taken from the {node} table,
-    // alias timestamp to revision_timestamp and add revision_uid.
-    $query = parent::buildQuery($ids, $revision_id);
-    $fields =& $query->getFields();
-    unset($fields['timestamp']);
-    $query->addField('revision', 'timestamp', 'revision_timestamp');
-    $fields['uid']['table'] = 'base';
-    $query->addField('revision', 'uid', 'revision_uid');
-    return $query;
-  }
-
-  /**
    * Overrides Drupal\Core\Entity\DatabaseStorageController::invokeHook().
    */
   protected function invokeHook($hook, EntityInterface $node) {
@@ -129,6 +114,16 @@ protected function invokeHook($hook, EntityInterface $node) {
   }
 
   /**
+   * Overrides \Drupal\Core\Entity\DatabaseStorageControllerNG::mapToDataStorageRecord().
+   */
+  protected function mapToDataStorageRecord(EntityInterface $entity, $langcode) {
+    // @todo Remove this once comment is a regular entity field.
+    $record = parent::mapToDataStorageRecord($entity, $langcode);
+    $record->comment = intval($record->comment);
+    return $record;
+  }
+
+  /**
    * Overrides Drupal\Core\Entity\DatabaseStorageController::preSave().
    */
   protected function preSave(EntityInterface $node) {
diff --git a/core/modules/node/lib/Drupal/node/Plugin/Core/Entity/Node.php b/core/modules/node/lib/Drupal/node/Plugin/Core/Entity/Node.php
index 92ed8e8..a3e22cb 100644
--- a/core/modules/node/lib/Drupal/node/Plugin/Core/Entity/Node.php
+++ b/core/modules/node/lib/Drupal/node/Plugin/Core/Entity/Node.php
@@ -28,7 +28,8 @@
  *   },
  *   translation_controller_class = "Drupal\node\NodeTranslationController",
  *   base_table = "node",
- *   revision_table = "node_revision",
+ *   data_table = "node_property_data",
+ *   revision_table = "node_property_revision",
  *   uri_callback = "node_uri",
  *   fieldable = TRUE,
  *   translatable = TRUE,
diff --git a/core/modules/node/node.install b/core/modules/node/node.install
index ebbce13..573bdba0 100644
--- a/core/modules/node/node.install
+++ b/core/modules/node/node.install
@@ -27,7 +27,7 @@ function node_schema() {
       // Defaults to NULL in order to avoid a brief period of potential
       // deadlocks on the index.
       'vid' => array(
-        'description' => 'The current {node_revision}.vid version identifier.',
+        'description' => 'The current {node_property_revision}.vid version identifier.',
         'type' => 'int',
         'unsigned' => TRUE,
         'not null' => FALSE,
@@ -47,56 +47,8 @@ function node_schema() {
         'not null' => TRUE,
         'default' => '',
       ),
-      'title' => array(
-        'description' => 'The title of this node, always treated as non-markup plain text.',
-        'type' => 'varchar',
-        'length' => 255,
-        'not null' => TRUE,
-        'default' => '',
-      ),
-      'uid' => array(
-        'description' => 'The {users}.uid that owns this node; initially, this is the user that created it.',
-        'type' => 'int',
-        'unsigned' => TRUE,
-        'not null' => TRUE,
-        'default' => 0,
-      ),
-      'status' => array(
-        'description' => 'Boolean indicating whether the node is published (visible to non-administrators).',
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => 1,
-      ),
-      'created' => array(
-        'description' => 'The Unix timestamp when the node was created.',
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => 0,
-      ),
-      'changed' => array(
-        'description' => 'The Unix timestamp when the node was most recently saved.',
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => 0,
-      ),
-      'comment' => array(
-        'description' => 'Whether comments are allowed on this node: 0 = no, 1 = closed (read only), 2 = open (read/write).',
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => 0,
-      ),
-      'promote' => array(
-        'description' => 'Boolean indicating whether the node should be displayed on the front page.',
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => 0,
-      ),
-      'sticky' => array(
-        'description' => 'Boolean indicating whether the node should be displayed at the top of lists in which it appears.',
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => 0,
-      ),
+      // @todo Remove the following columns when removing the legacy Content
+      //   Translation module.
       'tnid' => array(
         'description' => 'The translation set id for this node, which equals the node id of the source post in each set.',
         'type' => 'int',
@@ -112,15 +64,9 @@ function node_schema() {
       ),
     ),
     'indexes' => array(
-      'node_changed'        => array('changed'),
-      'node_created'        => array('created'),
-      'node_frontpage'      => array('promote', 'status', 'sticky', 'created'),
-      'node_status_type'    => array('status', 'type', 'nid'),
-      'node_title_type'     => array('title', array('type', 4)),
-      'node_type'           => array(array('type', 4)),
-      'uid'                 => array('uid'),
-      'tnid'                => array('tnid'),
-      'translate'           => array('translate'),
+      'node_type' => array(array('type', 4)),
+      'tnid' => array('tnid'),
+      'translate' => array('translate'),
     ),
     'unique keys' => array(
       'vid' => array('vid'),
@@ -128,76 +74,118 @@ function node_schema() {
     ),
     'foreign keys' => array(
       'node_revision' => array(
-        'table' => 'node_revision',
+        'table' => 'node_property_revision',
         'columns' => array('vid' => 'vid'),
       ),
-      'node_author' => array(
-        'table' => 'users',
-        'columns' => array('uid' => 'uid'),
-      ),
     ),
     'primary key' => array('nid'),
   );
 
-  $schema['node_access'] = array(
-    'description' => 'Identifies which realm/grant pairs a user must possess in order to view, update, or delete specific nodes.',
+  // Node property storage.
+  $schema['node_property_data'] = array(
+    'description' => 'Base table for node properties.',
     'fields' => array(
       'nid' => array(
-        'description' => 'The {node}.nid this record affects.',
-        'type' => 'int',
+        'description' => 'The primary identifier for a node.',
+        'type' => 'serial',
         'unsigned' => TRUE,
         'not null' => TRUE,
-        'default' => 0,
       ),
-      'gid' => array(
-        'description' => "The grant ID a user must possess in the specified realm to gain this row's privileges on the node.",
+      'vid' => array(
+        'description' => 'The current {node_property_revision}.vid version identifier.',
         'type' => 'int',
         'unsigned' => TRUE,
         'not null' => TRUE,
-        'default' => 0,
       ),
-      'realm' => array(
-        'description' => 'The realm in which the user must possess the grant ID. Each node access node can define one or more realms.',
+      'langcode' => array(
+        'description' => 'The {language}.langcode of these node property values.',
+        'type' => 'varchar',
+        'length' => 12,
+        'not null' => TRUE,
+        'default' => '',
+      ),
+      'default_langcode' => array(
+        'description' => 'Boolean indicating whether the property values are in the {language}.langcode of this node.',
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 1,
+      ),
+      'title' => array(
+        'description' => 'The title of this node, always treated as non-markup plain text.',
         'type' => 'varchar',
         'length' => 255,
         'not null' => TRUE,
         'default' => '',
       ),
-      'grant_view' => array(
-        'description' => 'Boolean indicating whether a user with the realm/grant pair can view this node.',
+      'uid' => array(
+        'description' => 'The {users}.uid that owns this node; initially, this is the user that created it.',
         'type' => 'int',
         'unsigned' => TRUE,
         'not null' => TRUE,
         'default' => 0,
-        'size' => 'tiny',
       ),
-      'grant_update' => array(
-        'description' => 'Boolean indicating whether a user with the realm/grant pair can edit this node.',
+      'status' => array(
+        'description' => 'Boolean indicating whether the node translation is published (visible to non-administrators).',
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 1,
+      ),
+      'created' => array(
+        'description' => 'The Unix timestamp when the node translation was created.',
         'type' => 'int',
-        'unsigned' => TRUE,
         'not null' => TRUE,
         'default' => 0,
-        'size' => 'tiny',
       ),
-      'grant_delete' => array(
-        'description' => 'Boolean indicating whether a user with the realm/grant pair can delete this node.',
+      'changed' => array(
+        'description' => 'The Unix timestamp when the node translation was most recently saved.',
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'comment' => array(
+        'description' => 'Whether comments are allowed on this node translation: 0 = no, 1 = closed (read only), 2 = open (read/write).',
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'promote' => array(
+        'description' => 'Boolean indicating whether the node translation should be displayed on the front page.',
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'sticky' => array(
+        'description' => 'Boolean indicating whether the node translation should be displayed at the top of lists in which it appears.',
         'type' => 'int',
-        'unsigned' => TRUE,
         'not null' => TRUE,
         'default' => 0,
-        'size' => 'tiny',
       ),
     ),
-    'primary key' => array('nid', 'gid', 'realm'),
+    'indexes' => array(
+      'node_changed' => array('changed'),
+      'node_created' => array('created'),
+      'node_frontpage' => array('promote', 'status', 'sticky', 'created'),
+      // @todo Figure out how to replace the 'node_status_type' and the
+      //   'node_title_type' indexes.
+      'nid' => array('nid'),
+      'vid' => array('vid'),
+      'uid' => array('uid'),
+    ),
     'foreign keys' => array(
-      'affected_node' => array(
+      'node_base' => array(
         'table' => 'node',
         'columns' => array('nid' => 'nid'),
       ),
-     ),
+      'node_author' => array(
+        'table' => 'users',
+        'columns' => array('uid' => 'uid'),
+      ),
+    ),
+    'primary key' => array('nid', 'vid', 'langcode'),
   );
 
-  $schema['node_revision'] = array(
+  // Node property revision storage.
+  $schema['node_property_revision'] = array(
     'description' => 'Stores information about each saved version of a {node}.',
     'fields' => array(
       'nid' => array(
@@ -205,7 +193,6 @@ function node_schema() {
         'type' => 'int',
         'unsigned' => TRUE,
         'not null' => TRUE,
-        'default' => 0,
       ),
       'vid' => array(
         'description' => 'The primary identifier for this version.',
@@ -213,29 +200,30 @@ function node_schema() {
         'unsigned' => TRUE,
         'not null' => TRUE,
       ),
-      'uid' => array(
-        'description' => 'The {users}.uid that created this version.',
+      'langcode' => array(
+        'description' => 'The {language}.langcode of this version.',
+        'type' => 'varchar',
+        'length' => 12,
+        'not null' => TRUE,
+        'default' => '',
+      ),
+      'default_langcode' => array(
+        'description' => 'Boolean indicating whether the property values of this version are in the {language}.langcode of this node.',
         'type' => 'int',
-        'unsigned' => TRUE,
         'not null' => TRUE,
-        'default' => 0,
+        'default' => 1,
       ),
       'title' => array(
-        'description' => 'The title of this version.',
+        'description' => 'The title of this version, always treated as non-markup plain text.',
         'type' => 'varchar',
         'length' => 255,
         'not null' => TRUE,
         'default' => '',
       ),
-      'log' => array(
-        'description' => 'The log entry explaining the changes in this version.',
-        'type' => 'text',
-        'not null' => TRUE,
-        'size' => 'big',
-      ),
-      'timestamp' => array(
-        'description' => 'A Unix timestamp indicating when this version was created.',
+      'uid' => array(
+        'description' => 'The {users}.uid that created this version.',
         'type' => 'int',
+        'unsigned' => TRUE,
         'not null' => TRUE,
         'default' => 0,
       ),
@@ -245,6 +233,18 @@ function node_schema() {
         'not null' => TRUE,
         'default' => 1,
       ),
+      'created' => array(
+        'description' => 'The Unix timestamp when the version was created.',
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'changed' => array(
+        'description' => 'The Unix timestamp when the version was most recently saved.',
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+      ),
       'comment' => array(
         'description' => 'Whether comments are allowed on this node (at the time of this revision): 0 = no, 1 = closed (read only), 2 = open (read/write).',
         'type' => 'int',
@@ -263,12 +263,18 @@ function node_schema() {
         'not null' => TRUE,
         'default' => 0,
       ),
+      'log' => array(
+        'description' => 'The log entry explaining the changes in this version.',
+        'type' => 'text',
+        'not null' => FALSE,
+        'size' => 'big',
+      ),
     ),
     'indexes' => array(
       'nid' => array('nid'),
       'uid' => array('uid'),
+      'vid' => array('vid'),
     ),
-    'primary key' => array('vid'),
     'foreign keys' => array(
       'versioned_node' => array(
         'table' => 'node',
@@ -279,6 +285,65 @@ function node_schema() {
         'columns' => array('uid' => 'uid'),
       ),
     ),
+    'primary key' => array('nid', 'vid', 'langcode'),
+  );
+
+  $schema['node_access'] = array(
+    'description' => 'Identifies which realm/grant pairs a user must possess in order to view, update, or delete specific nodes.',
+    'fields' => array(
+      'nid' => array(
+        'description' => 'The {node}.nid this record affects.',
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'gid' => array(
+        'description' => "The grant ID a user must possess in the specified realm to gain this row's privileges on the node.",
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'realm' => array(
+        'description' => 'The realm in which the user must possess the grant ID. Each node access node can define one or more realms.',
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => '',
+      ),
+      'grant_view' => array(
+        'description' => 'Boolean indicating whether a user with the realm/grant pair can view this node.',
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+        'size' => 'tiny',
+      ),
+      'grant_update' => array(
+        'description' => 'Boolean indicating whether a user with the realm/grant pair can edit this node.',
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+        'size' => 'tiny',
+      ),
+      'grant_delete' => array(
+        'description' => 'Boolean indicating whether a user with the realm/grant pair can delete this node.',
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+        'size' => 'tiny',
+      ),
+    ),
+    'primary key' => array('nid', 'gid', 'realm'),
+    'foreign keys' => array(
+      'affected_node' => array(
+        'table' => 'node',
+        'columns' => array('nid' => 'nid'),
+      ),
+    ),
   );
 
   $schema['node_type'] = array(
@@ -361,7 +426,7 @@ function node_schema() {
         'type' => 'int',
         'not null' => TRUE,
         'default' => 0,
-        'size' => 'tiny'
+        'size' => 'tiny',
       ),
       'orig_type' => array(
         'description' => 'The original machine-readable name of this node type. This may be different from the current type name if the locked field is 0.',
diff --git a/core/modules/node/node.module b/core/modules/node/node.module
index 1c0a10e..ede28ce 100644
--- a/core/modules/node/node.module
+++ b/core/modules/node/node.module
@@ -1607,7 +1607,7 @@ function _node_revision_access(EntityInterface $node, $op = 'view', $account = N
     // different revisions so there is no need for a separate database check.
     // Also, if you try to revert to or delete the default revision, that's
     // not good.
-    if ($node->isDefaultRevision() && (db_query('SELECT COUNT(vid) FROM {node_revision} WHERE nid = :nid', array(':nid' => $node->nid))->fetchField() == 1 || $op == 'update' || $op == 'delete')) {
+    if ($node->isDefaultRevision() && (db_query('SELECT COUNT(vid) FROM {node_property_revision} WHERE nid = :nid', array(':nid' => $node->nid))->fetchField() == 1 || $op == 'update' || $op == 'delete')) {
       $access[$cid] = FALSE;
     }
     elseif (user_access('administer nodes', $account)) {
@@ -1858,7 +1858,7 @@ function node_page_title(EntityInterface $node) {
  *   A unix timestamp indicating the last time the node was changed.
  */
 function node_last_changed($nid) {
-  return db_query('SELECT changed FROM {node} WHERE nid = :nid', array(':nid' => $nid))->fetch()->changed;
+  return db_query('SELECT changed FROM {node_property_data} WHERE nid = :nid', array(':nid' => $nid))->fetch()->changed;
 }
 
 /**
