diff --git a/core/lib/Drupal/Core/Entity/DatabaseStorageControllerNG.php b/core/lib/Drupal/Core/Entity/DatabaseStorageControllerNG.php
index 007d6d3..0209270 100644
--- a/core/lib/Drupal/Core/Entity/DatabaseStorageControllerNG.php
+++ b/core/lib/Drupal/Core/Entity/DatabaseStorageControllerNG.php
@@ -235,7 +235,15 @@ protected function invokeHook($hook, EntityInterface $entity) {
   protected function mapToStorageRecord(EntityInterface $entity) {
     $record = new \stdClass();
     foreach ($this->entityInfo['schema_fields_sql']['base table'] as $name) {
-      $record->$name = $entity->$name->value;
+      switch ($entity->$name->get('value')->getType()) {
+        // Store dates using timestamps.
+        case 'date':
+          $record->$name = $entity->$name->value->getTimestamp();
+          break;
+        default:
+          $record->$name = $entity->$name->value;
+          break;
+      }
     }
     return $record;
   }
diff --git a/core/lib/Drupal/Core/Entity/EntityNG.php b/core/lib/Drupal/Core/Entity/EntityNG.php
index 7520466..96fa602 100644
--- a/core/lib/Drupal/Core/Entity/EntityNG.php
+++ b/core/lib/Drupal/Core/Entity/EntityNG.php
@@ -292,11 +292,11 @@ public function translations() {
    * @see EntityNG::compatibilityMode
    */
   public function setCompatibilityMode($enabled) {
-    $this->compatibilityMode = (bool) $enabled;
-    if ($enabled) {
+    if (!$this->compatibilityMode && $enabled) {
       $this->updateOriginalValues();
       $this->fields = array();
     }
+    $this->compatibilityMode = (bool) $enabled;
   }
 
   /**
diff --git a/core/lib/Drupal/Core/Entity/EntityRenderController.php b/core/lib/Drupal/Core/Entity/EntityRenderController.php
index 2cd0578..55e1d2f 100644
--- a/core/lib/Drupal/Core/Entity/EntityRenderController.php
+++ b/core/lib/Drupal/Core/Entity/EntityRenderController.php
@@ -38,6 +38,10 @@ public function buildContent(array $entities = array(), $view_mode = 'full', $la
       drupal_alter('entity_view_mode', $view_mode, $entity, $context);
       $entity->content['#view_mode'] = $view_mode;
       $prepare[$view_mode][$key] = $entity;
+
+      if ($entity instanceof EntityNG) {
+        $entity->setCompatibilityMode(TRUE);
+      }
     }
 
     // Prepare and build field content, grouped by view mode.
@@ -61,6 +65,9 @@ public function buildContent(array $entities = array(), $view_mode = 'full', $la
       }
       foreach ($entities as $entity) {
         $entity->content += field_attach_view($this->entityType, $entity, $view_mode, $langcode);
+        if ($entity instanceof EntityNG) {
+          $entity->setCompatibilityMode(FALSE);
+        }
       }
     }
   }
diff --git a/core/modules/comment/comment.admin.inc b/core/modules/comment/comment.admin.inc
index dcbd1bc..c867232 100644
--- a/core/modules/comment/comment.admin.inc
+++ b/core/modules/comment/comment.admin.inc
@@ -109,31 +109,31 @@ function comment_admin_overview($form, &$form_state, $arg) {
   foreach ($comments as $comment) {
     // Remove the first node title from the node_titles array and attach to
     // the comment.
-    $comment->node_title = array_shift($node_titles);
+    $node_title = array_shift($node_titles);
     $comment_body = field_get_items('comment', $comment, 'comment_body');
-    $options[$comment->cid] = array(
+    $options[$comment->cid->value] = array(
       'subject' => array(
         'data' => array(
           '#type' => 'link',
-          '#title' => $comment->subject,
-          '#href' => 'comment/' . $comment->cid,
-          '#options' => array('attributes' => array('title' => truncate_utf8($comment_body[0]['value'], 128)), 'fragment' => 'comment-' . $comment->cid),
+          '#title' => $comment->subject->value,
+          '#href' => 'comment/' . $comment->cid->value,
+          '#options' => array('attributes' => array('title' => truncate_utf8($comment->comment_body->value, 128)), 'fragment' => 'comment-' . $comment->cid->value),
         ),
       ),
       'author' => theme('username', array('account' => $comment)),
       'posted_in' => array(
         'data' => array(
           '#type' => 'link',
-          '#title' => $comment->node_title,
-          '#href' => 'node/' . $comment->nid,
+          '#title' => $node_title,
+          '#href' => 'node/' . $comment->nid->value,
         ),
       ),
-      'changed' => format_date($comment->changed, 'short'),
+      'changed' => format_date($comment->changed->value->getTimestamp(), 'short'),
     );
     $links = array();
     $links['edit'] = array(
       'title' => t('edit'),
-      'href' => 'comment/' . $comment->cid . '/edit',
+      'href' => 'comment/' . $comment->cid->value . '/edit',
       'query' => $destination,
     );
     $options[$comment->cid]['operations']['data'] = array(
@@ -187,10 +187,10 @@ function comment_admin_overview_submit($form, &$form_state) {
       $comment = comment_load($value);
 
       if ($operation == 'unpublish') {
-        $comment->status = COMMENT_NOT_PUBLISHED;
+        $comment->status->value = COMMENT_NOT_PUBLISHED;
       }
       elseif ($operation == 'publish') {
-        $comment->status = COMMENT_PUBLISHED;
+        $comment->status->value = COMMENT_PUBLISHED;
       }
       comment_save($comment);
     }
@@ -219,7 +219,7 @@ function comment_multiple_delete_confirm($form, &$form_state) {
   $comment_counter = 0;
   foreach (array_filter($edit['comments']) as $cid => $value) {
     $comment = comment_load($cid);
-    if (is_object($comment) && is_numeric($comment->cid)) {
+    if (is_object($comment) && is_numeric($comment->cid->value)) {
       $subject = db_query('SELECT subject FROM {comment} WHERE cid = :cid', array(':cid' => $cid))->fetchField();
       $form['comments'][$cid] = array('#type' => 'hidden', '#value' => $cid, '#prefix' => '<li>', '#suffix' => check_plain($subject) . '</li>');
       $comment_counter++;
@@ -283,11 +283,11 @@ function comment_confirm_delete_page($cid) {
 function comment_confirm_delete($form, &$form_state, Comment $comment) {
   $form_state['comment'] = $comment;
   // Always provide entity id in the same form key as in the entity edit form.
-  $form['cid'] = array('#type' => 'value', '#value' => $comment->cid);
+  $form['cid'] = array('#type' => 'value', '#value' => $comment->cid->value);
   return confirm_form(
     $form,
-    t('Are you sure you want to delete the comment %title?', array('%title' => $comment->subject)),
-    'node/' . $comment->nid,
+    t('Are you sure you want to delete the comment %title?', array('%title' => $comment->subject->value)),
+    'node/' . $comment->nid->value,
     t('Any replies to this comment will be lost. This action cannot be undone.'),
     t('Delete'),
     t('Cancel'),
@@ -300,11 +300,11 @@ function comment_confirm_delete($form, &$form_state, Comment $comment) {
 function comment_confirm_delete_submit($form, &$form_state) {
   $comment = $form_state['comment'];
   // Delete the comment and its replies.
-  comment_delete($comment->cid);
+  comment_delete($comment->cid->value);
   drupal_set_message(t('The comment and all its replies have been deleted.'));
-  watchdog('content', 'Deleted comment @cid and its replies.', array('@cid' => $comment->cid));
+  watchdog('content', 'Deleted comment @cid and its replies.', array('@cid' => $comment->cid->value));
   // Clear the cache so an anonymous user sees that his comment was deleted.
   cache_invalidate(array('content' => TRUE));
 
-  $form_state['redirect'] = "node/$comment->nid";
+  $form_state['redirect'] = "node/{$comment->nid->value}";
 }
diff --git a/core/modules/comment/comment.api.php b/core/modules/comment/comment.api.php
index 95c3e1d..c8548a3 100644
--- a/core/modules/comment/comment.api.php
+++ b/core/modules/comment/comment.api.php
@@ -23,7 +23,7 @@
  */
 function hook_comment_presave(Drupal\comment\Comment $comment) {
   // Remove leading & trailing spaces from the comment subject.
-  $comment->subject = trim($comment->subject);
+  $comment->subject->value = trim($comment->subject->value);
 }
 
 /**
@@ -34,7 +34,7 @@ function hook_comment_presave(Drupal\comment\Comment $comment) {
  */
 function hook_comment_insert(Drupal\comment\Comment $comment) {
   // Reindex the node when comments are added.
-  search_touch_node($comment->nid);
+  search_touch_node($comment->nid->value);
 }
 
 /**
@@ -45,7 +45,7 @@ function hook_comment_insert(Drupal\comment\Comment $comment) {
  */
 function hook_comment_update(Drupal\comment\Comment $comment) {
   // Reindex the node when comments are updated.
-  search_touch_node($comment->nid);
+  search_touch_node($comment->nid->value);
 }
 
 /**
@@ -75,7 +75,7 @@ function hook_comment_load(Drupal\comment\Comment $comments) {
  */
 function hook_comment_view(Drupal\comment\Comment $comment, $view_mode, $langcode) {
   // how old is the comment
-  $comment->time_ago = time() - $comment->changed;
+  $comment->time_ago->value = time() - $comment->changed->value->getTimestamp();
 }
 
 /**
@@ -117,7 +117,7 @@ function hook_comment_view_alter(&$build, Drupal\comment\Comment $comment) {
  *   The comment the action is being performed on.
  */
 function hook_comment_publish(Drupal\comment\Comment $comment) {
-  drupal_set_message(t('Comment: @subject has been published', array('@subject' => $comment->subject)));
+  drupal_set_message(t('Comment: @subject has been published', array('@subject' => $comment->subject->value)));
 }
 
 /**
@@ -127,7 +127,7 @@ function hook_comment_publish(Drupal\comment\Comment $comment) {
  *   The comment the action is being performed on.
  */
 function hook_comment_unpublish(Drupal\comment\Comment $comment) {
-  drupal_set_message(t('Comment: @subject has been unpublished', array('@subject' => $comment->subject)));
+  drupal_set_message(t('Comment: @subject has been unpublished', array('@subject' => $comment->subject->value)));
 }
 
 /**
@@ -147,7 +147,7 @@ function hook_comment_unpublish(Drupal\comment\Comment $comment) {
 function hook_comment_predelete(Drupal\comment\Comment $comment) {
   // Delete a record associated with the comment in a custom table.
   db_delete('example_comment_table')
-    ->condition('cid', $comment->cid)
+    ->condition('cid', $comment->cid->value)
     ->execute();
 }
 
@@ -166,7 +166,7 @@ function hook_comment_predelete(Drupal\comment\Comment $comment) {
  * @see entity_delete_multiple()
  */
 function hook_comment_delete(Drupal\comment\Comment $comment) {
-  drupal_set_message(t('Comment: @subject has been deleted', array('@subject' => $comment->subject)));
+  drupal_set_message(t('Comment: @subject has been deleted', array('@subject' => $comment->subject->value)));
 }
 
 /**
diff --git a/core/modules/comment/comment.module b/core/modules/comment/comment.module
index df0a33a..58c5e84 100644
--- a/core/modules/comment/comment.module
+++ b/core/modules/comment/comment.module
@@ -178,8 +178,8 @@ function comment_node_type_load($name) {
  */
 function comment_uri(Comment $comment) {
   return array(
-    'path' => 'comment/' . $comment->cid,
-    'options' => array('fragment' => 'comment-' . $comment->cid),
+    'path' => 'comment/' . $comment->cid->value,
+    'options' => array('fragment' => 'comment-' . $comment->cid->value),
   );
 }
 
@@ -505,10 +505,10 @@ function comment_block_view($delta = '') {
  *   The comment listing set to the page on which the comment appears.
  */
 function comment_permalink($cid) {
-  if (($comment = comment_load($cid)) && ($node = node_load($comment->nid))) {
+  if (($comment = comment_load($cid)) && ($node = $comment->nid->entity)) {
 
     // Find the current display page for this comment.
-    $page = comment_get_display_page($comment->cid, $node->type);
+    $page = comment_get_display_page($comment->cid->value, $node->type);
 
     // @todo: Cleaner sub request handling.
     $request = drupal_container()->get('request');
@@ -628,7 +628,7 @@ function theme_comment_block() {
   $items = array();
   $number = variable_get('comment_block_count', 10);
   foreach (comment_get_recent($number) as $comment) {
-    $items[] = l($comment->subject, 'comment/' . $comment->cid, array('fragment' => 'comment-' . $comment->cid)) . '&nbsp;<span>' . t('@time ago', array('@time' => format_interval(REQUEST_TIME - $comment->changed))) . '</span>';
+    $items[] = l($comment->subject->value, 'comment/' . $comment->cid->value, array('fragment' => 'comment-' . $comment->cid->value)) . '&nbsp;<span>' . t('@time ago', array('@time' => format_interval(REQUEST_TIME - $comment->changed->value->getTimestamp()))) . '</span>';
   }
 
   if ($items) {
@@ -946,7 +946,7 @@ function comment_prepare_thread(&$comments) {
 
     // The $divs element instructs #prefix whether to add an indent div or
     // close existing divs (a negative value).
-    $comment->depth = count(explode('.', $comment->thread)) - 1;
+    $comment->depth = count(explode('.', $comment->thread->value)) - 1;
     if ($comment->depth > $divs) {
       $comment->divs = 1;
       $divs++;
@@ -999,25 +999,25 @@ function comment_links(Comment $comment, Node $node) {
     if (user_access('administer comments') && user_access('post comments')) {
       $links['comment-delete'] = array(
         'title' => t('delete'),
-        'href' => "comment/$comment->cid/delete",
+        'href' => "comment/{$comment->cid->value}/delete",
         'html' => TRUE,
       );
       $links['comment-edit'] = array(
         'title' => t('edit'),
-        'href' => "comment/$comment->cid/edit",
+        'href' => "comment/{$comment->cid->value}/edit",
         'html' => TRUE,
       );
       $links['comment-reply'] = array(
         'title' => t('reply'),
-        'href' => "comment/reply/$comment->nid/$comment->cid",
+        'href' => "comment/reply/{$comment->nid->value}/{$comment->cid->value}",
         'html' => TRUE,
       );
-      if ($comment->status == COMMENT_NOT_PUBLISHED) {
+      if ($comment->status->value == COMMENT_NOT_PUBLISHED) {
         $links['comment-approve'] = array(
           'title' => t('approve'),
-          'href' => "comment/$comment->cid/approve",
+          'href' => "comment/{$comment->cid->value}/approve",
           'html' => TRUE,
-          'query' => array('token' => drupal_get_token("comment/$comment->cid/approve")),
+          'query' => array('token' => drupal_get_token("comment/{$comment->cid->value}/approve")),
         );
       }
     }
@@ -1025,13 +1025,13 @@ function comment_links(Comment $comment, Node $node) {
       if (comment_access('edit', $comment)) {
         $links['comment-edit'] = array(
           'title' => t('edit'),
-          'href' => "comment/$comment->cid/edit",
+          'href' => "comment/{$comment->cid->value}/edit",
           'html' => TRUE,
         );
       }
       $links['comment-reply'] = array(
         'title' => t('reply'),
-        'href' => "comment/reply/$comment->nid/$comment->cid",
+        'href' => "comment/reply/{$comment->nid->value}/{$comment->cid->value}",
         'html' => TRUE,
       );
     }
@@ -1339,7 +1339,7 @@ function comment_user_cancel($edit, $account, $method) {
     case 'user_cancel_block_unpublish':
       $comments = entity_load_multiple_by_properties('comment', array('uid' => $account->uid));
       foreach ($comments as $comment) {
-        $comment->status = 0;
+        $comment->status->value = 0;
         comment_save($comment);
       }
       break;
@@ -1347,7 +1347,7 @@ function comment_user_cancel($edit, $account, $method) {
     case 'user_cancel_reassign':
       $comments = entity_load_multiple_by_properties('comment', array('uid' => $account->uid));
       foreach ($comments as $comment) {
-        $comment->uid = 0;
+        $comment->uid->value = 0;
         comment_save($comment);
       }
       break;
@@ -1382,7 +1382,7 @@ function comment_access($op, Comment $comment) {
   global $user;
 
   if ($op == 'edit') {
-    return ($user->uid && $user->uid == $comment->uid && $comment->status == COMMENT_PUBLISHED && user_access('edit own comments')) || user_access('administer comments');
+    return ($user->uid && $user->uid == $comment->uid->value && $comment->status->value == COMMENT_PUBLISHED && user_access('edit own comments')) || user_access('administer comments');
   }
 }
 
@@ -1562,7 +1562,7 @@ function comment_get_display_page($cid, $node_type) {
  * @see comment_menu()
  */
 function comment_edit_page(Comment $comment) {
-  drupal_set_title(t('Edit comment %comment', array('%comment' => $comment->subject)), PASS_THROUGH);
+  drupal_set_title(t('Edit comment %comment', array('%comment' => $comment->subject->value)), PASS_THROUGH);
   return entity_get_form($comment);
 }
 
@@ -1576,29 +1576,28 @@ function comment_preview(Comment $comment) {
   $preview_build = array();
 
   if (!form_get_errors()) {
-    $comment_body = field_get_items('comment', $comment, 'comment_body');
-    $comment->format = $comment_body[0]['format'];
+    $comment->format = $comment->comment_body->format;
     // Attach the user and time information.
-    if (!empty($comment->name)) {
-      $account = user_load_by_name($comment->name);
+    if (!empty($comment->name->value)) {
+      $account = user_load_by_name($comment->name->value);
     }
     elseif ($user->uid && empty($comment->is_anonymous)) {
       $account = $user;
     }
 
     if (!empty($account->uid)) {
-      $comment->uid = $account->uid;
-      $comment->name = check_plain($account->name);
+      $comment->uid->value = $account->uid;
+      $comment->name->value = check_plain($account->name);
       $comment->signature = $account->signature;
       $comment->signature_format = $account->signature_format;
       $comment->picture = $account->picture;
     }
-    elseif (empty($comment->name)) {
-      $comment->name = config('user.settings')->get('anonymous');
+    elseif (empty($comment->name->value)) {
+      $comment->name->value = config('user.settings')->get('anonymous');
     }
 
-    $comment->created = !empty($comment->created) ? $comment->created : REQUEST_TIME;
-    $comment->changed = REQUEST_TIME;
+    $comment->created->value = !empty($comment->created->value) ? $comment->created->value : REQUEST_TIME;
+    $comment->changed->value = REQUEST_TIME;
     $comment->in_preview = TRUE;
     $comment_build = comment_view($comment);
     $comment_build['#weight'] = -100;
@@ -1606,15 +1605,15 @@ function comment_preview(Comment $comment) {
     $preview_build['comment_preview'] = $comment_build;
   }
 
-  if ($comment->pid) {
+  if ($comment->pid->value) {
     $build = array();
-    $comment = comment_load($comment->pid);
-    if ($comment && $comment->status == COMMENT_PUBLISHED) {
+    $comment = comment_load($comment->pid->value);
+    if ($comment && $comment->status->value == COMMENT_PUBLISHED) {
       $build = comment_view($comment);
     }
   }
   else {
-    $build = node_view(node_load($comment->nid));
+    $build = node_view($comment->nid->entity);
   }
 
   $preview_build['comment_output_below'] = $build;
@@ -1642,23 +1641,28 @@ function template_preprocess_comment(&$variables) {
   $node = $variables['elements']['#node'];
   $variables['comment'] = $comment;
   $variables['node'] = $node;
-  $variables['author'] = theme('username', array('account' => $comment));
-  $variables['created'] = format_date($comment->created);
-  $variables['changed'] = format_date($comment->changed);
+  // Create a fake-account object for theming the given username.
+  // @todo: Clean this up.
+  $account = (object) array('uid' => $comment->uid->value, 'name' => $comment->name->value, 'homepage' => $comment->homepage->value);
+  $variables['author'] = theme('username', array('account' => $account));
+  $variables['created'] = format_date($comment->created->value->getTimestamp());
+  $variables['changed'] = format_date($comment->changed->value->getTimestamp());
 
   $variables['new'] = !empty($comment->new) ? t('new') : '';
-  $variables['user_picture'] = theme_get_setting('toggle_comment_user_picture') ? theme('user_picture', array('account' => $comment)) : '';
+  $variables['user_picture'] = theme_get_setting('toggle_comment_user_picture') ? theme('user_picture', array('account' => $account)) : '';
   $variables['signature'] = $comment->signature;
 
   $uri = $comment->uri();
   $uri['options'] += array('attributes' => array('class' => 'permalink', 'rel' => 'bookmark'));
 
-  $variables['title'] = l($comment->subject, $uri['path'], $uri['options']);
+  $variables['title'] = l($comment->subject->value, $uri['path'], $uri['options']);
   $variables['permalink'] = l(t('Permalink'), $uri['path'], $uri['options']);
   $variables['submitted'] = t('Submitted by !username on !datetime', array('!username' => $variables['author'], '!datetime' => $variables['created']));
 
   // Preprocess fields.
+  $comment->setCompatibilityMode(TRUE);
   field_attach_preprocess('comment', $comment, $variables['elements'], $variables);
+  $comment->setCompatibilityMode(FALSE);
 
   // Helpful $content variable for templates.
   foreach (element_children($variables['elements']) as $key) {
@@ -1670,7 +1674,7 @@ function template_preprocess_comment(&$variables) {
     $variables['status'] = 'preview';
   }
   else {
-    $variables['status'] = ($comment->status == COMMENT_NOT_PUBLISHED) ? 'unpublished' : 'published';
+    $variables['status'] = ($comment->status->value == COMMENT_NOT_PUBLISHED) ? 'unpublished' : 'published';
   }
 
   // Gather comment classes.
@@ -1681,14 +1685,14 @@ function template_preprocess_comment(&$variables) {
   if ($variables['new']) {
     $variables['attributes']['class'][] = 'new';
   }
-  if (!$comment->uid) {
+  if (!$comment->uid->value) {
     $variables['attributes']['class'][] = 'by-anonymous';
   }
   else {
-    if ($comment->uid == $variables['node']->uid) {
+    if ($comment->uid->value == $variables['node']->uid) {
       $variables['attributes']['class'][] = 'by-node-author';
     }
-    if ($comment->uid == $variables['user']->uid) {
+    if ($comment->uid->value == $variables['user']->uid) {
       $variables['attributes']['class'][] = 'by-viewer';
     }
   }
@@ -1850,9 +1854,9 @@ function comment_action_info() {
  * @ingroup actions
  */
 function comment_publish_action(Comment $comment = NULL, $context = array()) {
-  if (isset($comment->subject)) {
-    $subject = $comment->subject;
-    $comment->status = COMMENT_PUBLISHED;
+  if (isset($comment->subject->value)) {
+    $subject = $comment->subject->value;
+    $comment->status->value = COMMENT_PUBLISHED;
   }
   else {
     $cid = $context['cid'];
@@ -1877,9 +1881,9 @@ function comment_publish_action(Comment $comment = NULL, $context = array()) {
  * @ingroup actions
  */
 function comment_unpublish_action(Comment $comment = NULL, $context = array()) {
-  if (isset($comment->subject)) {
-    $subject = $comment->subject;
-    $comment->status = COMMENT_NOT_PUBLISHED;
+  if (isset($comment->subject->value)) {
+    $subject = $comment->subject->value;
+    $comment->status->value = COMMENT_NOT_PUBLISHED;
   }
   else {
     $cid = $context['cid'];
@@ -1910,8 +1914,8 @@ function comment_unpublish_by_keyword_action(Comment $comment, $context) {
   foreach ($context['keywords'] as $keyword) {
     $text = drupal_render($comment);
     if (strpos($text, $keyword) !== FALSE) {
-      $comment->status = COMMENT_NOT_PUBLISHED;
-      watchdog('action', 'Unpublished comment %subject.', array('%subject' => $comment->subject));
+      $comment->status->value = COMMENT_NOT_PUBLISHED;
+      watchdog('action', 'Unpublished comment %subject.', array('%subject' => $comment->subject->value));
       break;
     }
   }
@@ -1954,7 +1958,7 @@ function comment_unpublish_by_keyword_action_submit($form, $form_state) {
 function comment_save_action(Comment $comment) {
   comment_save($comment);
   cache_invalidate(array('content' => TRUE));
-  watchdog('action', 'Saved comment %title', array('%title' => $comment->subject));
+  watchdog('action', 'Saved comment %title', array('%title' => $comment->subject->value));
 }
 
 /**
diff --git a/core/modules/comment/comment.pages.inc b/core/modules/comment/comment.pages.inc
index 3d1ecb9..b3cded0 100644
--- a/core/modules/comment/comment.pages.inc
+++ b/core/modules/comment/comment.pages.inc
@@ -56,18 +56,18 @@ function comment_reply(Node $node, $pid = NULL) {
       if (user_access('access comments')) {
         // Load the parent comment.
         $comment = comment_load($pid);
-        if ($comment->status == COMMENT_PUBLISHED) {
+        if ($comment->status->value == COMMENT_PUBLISHED) {
           // If that comment exists, make sure that the current comment and the
           // parent comment both belong to the same parent node.
-          if ($comment->nid != $node->nid) {
+          if ($comment->nid->value != $node->nid) {
             // Attempting to reply to a comment not belonging to the current nid.
             drupal_set_message(t('The comment you are replying to does not exist.'), 'error');
             drupal_goto("node/$node->nid");
           }
           // Display the parent comment
-          $comment->node_type = 'comment_node_' . $node->type;
-          field_attach_load('comment', array($comment->cid => $comment));
-          $comment->name = $comment->uid ? $comment->registered_name : $comment->name;
+          $comment->node_type->value = 'comment_node_' . $node->type;
+          field_attach_load('comment', array($comment->cid->value => $comment));
+          $comment->name->value = $comment->uid->value ? $comment->registered_name : $comment->name->value;
           $build['comment_parent'] = comment_view($comment);
         }
         else {
@@ -120,11 +120,11 @@ function comment_approve($cid) {
   }
 
   if ($comment = comment_load($cid)) {
-    $comment->status = COMMENT_PUBLISHED;
+    $comment->status->value = COMMENT_PUBLISHED;
     comment_save($comment);
 
     drupal_set_message(t('Comment approved.'));
-    drupal_goto('node/' . $comment->nid);
+    drupal_goto('node/' . $comment->nid->value);
   }
   throw new NotFoundHttpException();
 }
diff --git a/core/modules/comment/comment.tokens.inc b/core/modules/comment/comment.tokens.inc
index c77cb67..97df04d 100644
--- a/core/modules/comment/comment.tokens.inc
+++ b/core/modules/comment/comment.tokens.inc
@@ -122,36 +122,36 @@ function comment_tokens($type, $tokens, array $data = array(), array $options =
       switch ($name) {
         // Simple key values on the comment.
         case 'cid':
-          $replacements[$original] = $comment->cid;
+          $replacements[$original] = $comment->cid->value;
           break;
 
         // Poster identity information for comments
         case 'hostname':
-          $replacements[$original] = $sanitize ? check_plain($comment->hostname) : $comment->hostname;
+          $replacements[$original] = $sanitize ? check_plain($comment->hostname->value) : $comment->hostname->value;
           break;
 
         case 'name':
-          $name = ($comment->uid == 0) ? config('user.settings')->get('anonymous') : $comment->name;
+          $name = ($comment->uid->value == 0) ? config('user.settings')->get('anonymous') : $comment->name->value;
           $replacements[$original] = $sanitize ? filter_xss($name) : $name;
           break;
 
         case 'mail':
-          if ($comment->uid != 0) {
-            $account = user_load($comment->uid);
+          if ($comment->uid->value != 0) {
+            $account = user_load($comment->uid->value);
             $mail = $account->mail;
           }
           else {
-            $mail = $comment->mail;
+            $mail = $comment->mail->value;
           }
           $replacements[$original] = $sanitize ? check_plain($mail) : $mail;
           break;
 
         case 'homepage':
-          $replacements[$original] = $sanitize ? check_url($comment->homepage) : $comment->homepage;
+          $replacements[$original] = $sanitize ? check_url($comment->homepage->value) : $comment->homepage->value;
           break;
 
         case 'title':
-          $replacements[$original] = $sanitize ? filter_xss($comment->subject) : $comment->subject;
+          $replacements[$original] = $sanitize ? filter_xss($comment->subject->value) : $comment->subject->value;
           break;
 
         case 'body':
@@ -164,37 +164,37 @@ function comment_tokens($type, $tokens, array $data = array(), array $options =
 
         // Comment related URLs.
         case 'url':
-          $url_options['fragment']  = 'comment-' . $comment->cid;
-          $replacements[$original] = url('comment/' . $comment->cid, $url_options);
+          $url_options['fragment']  = 'comment-' . $comment->cid->value;
+          $replacements[$original] = url('comment/' . $comment->cid->value, $url_options);
           break;
 
         case 'edit-url':
           $url_options['fragment'] = NULL;
-          $replacements[$original] = url('comment/' . $comment->cid . '/edit', $url_options);
+          $replacements[$original] = url('comment/' . $comment->cid->value . '/edit', $url_options);
           break;
 
         // Default values for the chained tokens handled below.
         case 'author':
-          $replacements[$original] = $sanitize ? filter_xss($comment->name) : $comment->name;
+          $replacements[$original] = $sanitize ? filter_xss($comment->name->value) : $comment->name->value;
           break;
 
         case 'parent':
-          if (!empty($comment->pid)) {
-            $parent = comment_load($comment->pid);
+          if (!empty($comment->pid->value)) {
+            $parent = comment_load($comment->pid->value);
             $replacements[$original] = $sanitize ? filter_xss($parent->subject) : $parent->subject;
           }
           break;
 
         case 'created':
-          $replacements[$original] = format_date($comment->created, 'medium', '', NULL, $langcode);
+          $replacements[$original] = format_date($comment->created->value->getTimestamp(), 'medium', '', NULL, $langcode);
           break;
 
         case 'changed':
-          $replacements[$original] = format_date($comment->changed, 'medium', '', NULL, $langcode);
+          $replacements[$original] = format_date($comment->changed->value->getTimestamp(), 'medium', '', NULL, $langcode);
           break;
 
         case 'node':
-          $node = node_load($comment->nid);
+          $node = $comment->nid->entity;
           $title = $node->label();
           $replacements[$original] = $sanitize ? filter_xss($title) : $title;
           break;
@@ -203,23 +203,23 @@ function comment_tokens($type, $tokens, array $data = array(), array $options =
 
     // Chained token relationships.
     if ($node_tokens = token_find_with_prefix($tokens, 'node')) {
-      $node = node_load($comment->nid);
+      $node = $comment->nid->entity;
       $replacements += token_generate('node', $node_tokens, array('node' => $node), $options);
     }
 
     if ($date_tokens = token_find_with_prefix($tokens, 'created')) {
-      $replacements += token_generate('date', $date_tokens, array('date' => $comment->created), $options);
+      $replacements += token_generate('date', $date_tokens, array('date' => $comment->created->value->getTimestamp()), $options);
     }
 
     if ($date_tokens = token_find_with_prefix($tokens, 'changed')) {
-      $replacements += token_generate('date', $date_tokens, array('date' => $comment->changed), $options);
+      $replacements += token_generate('date', $date_tokens, array('date' => $comment->changed->value->getTimestamp()), $options);
     }
 
-    if (($parent_tokens = token_find_with_prefix($tokens, 'parent')) && $parent = comment_load($comment->pid)) {
+    if (($parent_tokens = token_find_with_prefix($tokens, 'parent')) && $parent = $comment->pid->entity) {
       $replacements += token_generate('comment', $parent_tokens, array('comment' => $parent), $options);
     }
 
-    if (($author_tokens = token_find_with_prefix($tokens, 'author')) && $account = user_load($comment->uid)) {
+    if (($author_tokens = token_find_with_prefix($tokens, 'author')) && $account = $comment->uid->entity) {
       $replacements += token_generate('user', $author_tokens, array('user' => $account), $options);
     }
   }
diff --git a/core/modules/comment/lib/Drupal/comment/Comment.php b/core/modules/comment/lib/Drupal/comment/Comment.php
index ef6c16a..fbde08b 100644
--- a/core/modules/comment/lib/Drupal/comment/Comment.php
+++ b/core/modules/comment/lib/Drupal/comment/Comment.php
@@ -8,31 +8,35 @@
 namespace Drupal\comment;
 
 use Drupal\Core\Entity\ContentEntityInterface;
-use Drupal\Core\Entity\Entity;
+use Drupal\Core\Entity\EntityNG;
 
 /**
  * Defines the comment entity class.
  */
-class Comment extends Entity implements ContentEntityInterface {
+class Comment extends EntityNG implements ContentEntityInterface {
 
   /**
    * The comment ID.
    *
-   * @var integer
+   * @todo: Rename to 'id'.
+   *
+   * @var \Drupal\Core\Entity\Property\ItemListInterface
    */
   public $cid;
 
   /**
    * The comment UUID.
    *
-   * @var string
+   * @var \Drupal\Core\Entity\Property\ItemListInterface
    */
   public $uuid;
 
   /**
    * The parent comment ID if this is a reply to a comment.
    *
-   * @var integer
+   * @todo: Rename to 'parent_id'.
+   *
+   * @var \Drupal\Core\Entity\Property\ItemListInterface
    */
   public $pid;
 
@@ -44,14 +48,14 @@ class Comment extends Entity implements ContentEntityInterface {
   /**
    * The comment language code.
    *
-   * @var string
+   * @var \Drupal\Core\Entity\Property\ItemListInterface
    */
-  public $langcode = LANGUAGE_NOT_SPECIFIED;
+  public $langcode;
 
   /**
    * The comment title.
    *
-   * @var string
+   * @var \Drupal\Core\Entity\Property\ItemListInterface
    */
   public $subject;
 
@@ -59,7 +63,9 @@ class Comment extends Entity implements ContentEntityInterface {
   /**
    * The comment author ID.
    *
-   * @var integer
+   * @todo: Rename to 'user_id'.
+   *
+   * @var \Drupal\Core\Entity\Property\ItemListInterface
    */
   public $uid = 0;
 
@@ -68,16 +74,16 @@ class Comment extends Entity implements ContentEntityInterface {
    *
    * For anonymous authors, this is the value as typed in the comment form.
    *
-   * @var string
+   * @var \Drupal\Core\Entity\Property\ItemListInterface
    */
-  public $name = '';
+  public $name;
 
   /**
    * The comment author's e-mail address.
    *
    * For anonymous authors, this is the value as typed in the comment form.
    *
-   * @var string
+   * @var \Drupal\Core\Entity\Property\ItemListInterface
    */
   public $mail;
 
@@ -86,21 +92,52 @@ class Comment extends Entity implements ContentEntityInterface {
    *
    * For anonymous authors, this is the value as typed in the comment form.
    *
-   * @var string
+   * @var \Drupal\Core\Entity\Property\ItemListInterface
    */
   public $homepage;
 
   /**
+   * The plain data values of the contained properties.
+   *
+   * Define some default values used.
+   *
+   * @var array
+   */
+  protected $values = array(
+    'langcode' => array(LANGUAGE_DEFAULT => array(0 => array('value' => LANGUAGE_NOT_SPECIFIED))),
+    'name' => array(LANGUAGE_DEFAULT => array(0 => array('value' => ''))),
+    'uid' => array(LANGUAGE_DEFAULT => array(0 => array('value' => 0))),
+  );
+
+  /**
+   * Overrides Entity::__construct().
+   */
+  public function __construct(array $values, $entity_type) {
+    parent::__construct($values, $entity_type);
+
+    // We unset all defined properties, so magic getters apply.
+    unset($this->cid);
+    unset($this->langcode);
+    unset($this->uuid);
+    unset($this->pid);
+    unset($this->subject);
+    unset($this->uid);
+    unset($this->name);
+    unset($this->mail);
+    unset($this->homepage);
+  }
+
+  /**
    * Implements Drupal\Core\Entity\EntityInterface::id().
    */
   public function id() {
-    return $this->cid;
+    return $this->get('cid')->value;
   }
 
   /**
    * Implements Drupal\Core\Entity\EntityInterface::bundle().
    */
   public function bundle() {
-    return $this->node_type;
+    return $this->get('node_type')->value;
   }
 }
diff --git a/core/modules/comment/lib/Drupal/comment/CommentFormController.php b/core/modules/comment/lib/Drupal/comment/CommentFormController.php
index cead0cd..2df1500 100644
--- a/core/modules/comment/lib/Drupal/comment/CommentFormController.php
+++ b/core/modules/comment/lib/Drupal/comment/CommentFormController.php
@@ -8,12 +8,12 @@
 namespace Drupal\comment;
 
 use Drupal\Core\Entity\EntityInterface;
-use Drupal\Core\Entity\EntityFormController;
+use Drupal\Core\Entity\EntityFormControllerNG;
 
 /**
  * Base for controller for comment forms.
  */
-class CommentFormController extends EntityFormController {
+class CommentFormController extends EntityFormControllerNG {
 
   /**
    * Overrides Drupal\Core\Entity\EntityFormController::form().
@@ -21,7 +21,7 @@ class CommentFormController extends EntityFormController {
   public function form(array $form, array &$form_state, EntityInterface $comment) {
     global $user;
 
-    $node = node_load($comment->nid);
+    $node = $comment->nid->entity;
     $form_state['comment']['node'] = $node;
 
     // Use #comment-form as unique jump target, regardless of node type.
@@ -29,7 +29,7 @@ public function form(array $form, array &$form_state, EntityInterface $comment)
     $form['#theme'] = array('comment_form__node_' . $node->type, 'comment_form');
 
     $anonymous_contact = variable_get('comment_anonymous_' . $node->type, COMMENT_ANONYMOUS_MAYNOT_CONTACT);
-    $is_admin = (!empty($comment->cid) && user_access('administer comments'));
+    $is_admin = (!empty($comment->cid->value) && user_access('administer comments'));
 
     if (!$user->uid && $anonymous_contact != COMMENT_ANONYMOUS_MAYNOT_CONTACT) {
       $form['#attached']['library'][] = array('system', 'jquery.cookie');
@@ -38,8 +38,8 @@ public function form(array $form, array &$form_state, EntityInterface $comment)
 
     // If not replying to a comment, use our dedicated page callback for new
     // comments on nodes.
-    if (empty($comment->cid) && empty($comment->pid)) {
-      $form['#action'] = url('comment/reply/' . $comment->nid);
+    if (empty($comment->cid->value) && empty($comment->pid->value)) {
+      $form['#action'] = url('comment/reply/' . $comment->nid->value);
     }
 
     if (isset($form_state['comment_preview'])) {
@@ -61,16 +61,16 @@ public function form(array $form, array &$form_state, EntityInterface $comment)
 
     // Prepare default values for form elements.
     if ($is_admin) {
-      $author = (!$comment->uid && $comment->name ? $comment->name : $comment->registered_name);
-      $status = (isset($comment->status) ? $comment->status : COMMENT_NOT_PUBLISHED);
-      $date = (!empty($comment->date) ? $comment->date : format_date($comment->created, 'custom', 'Y-m-d H:i O'));
+      $author = (!$comment->uid->value && $comment->name->value ? $comment->name->value : $comment->registered_name);
+      $status = (isset($comment->status->value) ? $comment->status->value : COMMENT_NOT_PUBLISHED);
+      $date = (!empty($comment->date) ? $comment->date : format_date($comment->created->value->getTimestamp(), 'custom', 'Y-m-d H:i O'));
     }
     else {
       if ($user->uid) {
         $author = $user->name;
       }
       else {
-        $author = ($comment->name ? $comment->name : '');
+        $author = ($comment->name->value ? $comment->name->value : '');
       }
       $status = (user_access('skip comment approval') ? COMMENT_PUBLISHED : COMMENT_NOT_PUBLISHED);
       $date = '';
@@ -115,7 +115,7 @@ public function form(array $form, array &$form_state, EntityInterface $comment)
     $form['author']['mail'] = array(
       '#type' => 'email',
       '#title' => t('E-mail'),
-      '#default_value' => $comment->mail,
+      '#default_value' => $comment->mail->value,
       '#required' => (!$user->uid && $anonymous_contact == COMMENT_ANONYMOUS_MUST_CONTACT),
       '#maxlength' => 64,
       '#size' => 30,
@@ -126,7 +126,7 @@ public function form(array $form, array &$form_state, EntityInterface $comment)
     $form['author']['homepage'] = array(
       '#type' => 'url',
       '#title' => t('Homepage'),
-      '#default_value' => $comment->homepage,
+      '#default_value' => $comment->homepage->value,
       '#maxlength' => 255,
       '#size' => 30,
       '#access' => $is_admin || (!$user->uid && $anonymous_contact != COMMENT_ANONYMOUS_MAYNOT_CONTACT),
@@ -157,19 +157,19 @@ public function form(array $form, array &$form_state, EntityInterface $comment)
       '#type' => 'textfield',
       '#title' => t('Subject'),
       '#maxlength' => 64,
-      '#default_value' => $comment->subject,
+      '#default_value' => $comment->subject->value,
       '#access' => variable_get('comment_subject_field_' . $node->type, 1) == 1,
     );
 
     // Used for conditional validation of author fields.
     $form['is_anonymous'] = array(
       '#type' => 'value',
-      '#value' => ($comment->cid ? !$comment->uid : !$user->uid),
+      '#value' => ($comment->cid->value ? !$comment->uid->value : !$user->uid),
     );
 
     // Add internal comment properties.
     foreach (array('cid', 'pid', 'nid', 'uid') as $key) {
-      $form[$key] = array('#type' => 'value', '#value' => $comment->$key);
+      $form[$key] = array('#type' => 'value', '#value' => $comment->$key->value);
     }
     $form['node_type'] = array('#type' => 'value', '#value' => 'comment_node_' . $node->type);
 
@@ -177,16 +177,16 @@ public function form(array $form, array &$form_state, EntityInterface $comment)
     // set.
     if ($comment->isNew()) {
       $language_content = language(LANGUAGE_TYPE_CONTENT);
-      $comment->langcode = $language_content->langcode;
+      $comment->langcode->value = $language_content->langcode;
     }
 
     $form['langcode'] = array(
       '#type' => 'value',
-      '#value' => $comment->langcode,
+      '#value' => $comment->langcode->value,
     );
 
     // Attach fields.
-    $comment->node_type = 'comment_node_' . $node->type;
+    $comment->node_type->value = 'comment_node_' . $node->type;
 
     return parent::form($form, $form_state, $comment);
   }
@@ -205,7 +205,7 @@ protected function actions(array $form, array &$form_state) {
 
     // Only show the save button if comment previews are optional or if we are
     // already previewing the submission.
-    $element['submit']['#access'] = ($comment->cid && user_access('administer comments')) || $preview_mode != DRUPAL_REQUIRED || isset($form_state['comment_preview']);
+    $element['submit']['#access'] = ($comment->cid->value && user_access('administer comments')) || $preview_mode != DRUPAL_REQUIRED || isset($form_state['comment_preview']);
 
     $element['preview'] = array(
       '#type' => 'submit',
@@ -271,42 +271,34 @@ public function submit(array $form, array &$form_state) {
     if (empty($comment->date)) {
       $comment->date = 'now';
     }
-    $comment->created = strtotime($comment->date);
-    $comment->changed = REQUEST_TIME;
+    $comment->created->value = strtotime($comment->date);
+    $comment->changed->value = REQUEST_TIME;
 
     // If the comment was posted by a registered user, assign the author's ID.
     // @todo Too fragile. Should be prepared and stored in comment_form()
     // already.
-    if (!$comment->is_anonymous && !empty($comment->name) && ($account = user_load_by_name($comment->name))) {
-      $comment->uid = $account->uid;
+    if (!$comment->is_anonymous && !empty($comment->name->value) && ($account = user_load_by_name($comment->name->value))) {
+      $comment->uid->value = $account->uid;
     }
     // If the comment was posted by an anonymous user and no author name was
     // required, use "Anonymous" by default.
-    if ($comment->is_anonymous && (!isset($comment->name) || $comment->name === '')) {
-      $comment->name = config('user.settings')->get('anonymous');
+    if ($comment->is_anonymous && (!isset($comment->name->value) || $comment->name->value === '')) {
+      $comment->name->value = config('user.settings')->get('anonymous');
     }
 
     // Validate the comment's subject. If not specified, extract from comment
     // body.
-    if (trim($comment->subject) == '') {
+    if (trim($comment->subject->value) == '') {
       // The body may be in any format, so:
       // 1) Filter it into HTML
       // 2) Strip out all HTML tags
       // 3) Convert entities back to plain-text.
-      $field = field_info_field('comment_body');
-      $langcode = field_is_translatable('comment', $field) ? $this->getFormLangcode($form_state) : LANGUAGE_NOT_SPECIFIED;
-      $comment_body = $comment->comment_body[$langcode][0];
-      if (isset($comment_body['format'])) {
-        $comment_text = check_markup($comment_body['value'], $comment_body['format']);
-      }
-      else {
-        $comment_text = check_plain($comment_body['value']);
-      }
+      $comment_text = $comment->comment_body->processed;
       $comment->subject = truncate_utf8(trim(decode_entities(strip_tags($comment_text))), 29, TRUE);
       // Edge cases where the comment body is populated only by HTML tags will
       // require a default subject.
-      if ($comment->subject == '') {
-        $comment->subject = t('(No subject)');
+      if ($comment->subject->value == '') {
+        $comment->subject->value = t('(No subject)');
       }
     }
 
@@ -342,13 +334,13 @@ public function save(array $form, array &$form_state) {
       }
 
       comment_save($comment);
-      $form_state['values']['cid'] = $comment->cid;
+      $form_state['values']['cid'] = $comment->cid->value;
 
       // Add an entry to the watchdog log.
-      watchdog('content', 'Comment posted: %subject.', array('%subject' => $comment->subject), WATCHDOG_NOTICE, l(t('view'), 'comment/' . $comment->cid, array('fragment' => 'comment-' . $comment->cid)));
+      watchdog('content', 'Comment posted: %subject.', array('%subject' => $comment->subject->value), WATCHDOG_NOTICE, l(t('view'), 'comment/' . $comment->cid->value, array('fragment' => 'comment-' . $comment->cid->value)));
 
       // Explain the approval queue if necessary.
-      if ($comment->status == COMMENT_NOT_PUBLISHED) {
+      if ($comment->status->value == COMMENT_NOT_PUBLISHED) {
         if (!user_access('administer comments')) {
           drupal_set_message(t('Your comment has been queued for review by site administrators and will be published after approval.'));
         }
@@ -358,16 +350,16 @@ public function save(array $form, array &$form_state) {
       }
       $query = array();
       // Find the current display page for this comment.
-      $page = comment_get_display_page($comment->cid, $node->type);
+      $page = comment_get_display_page($comment->cid->value, $node->type);
       if ($page > 0) {
         $query['page'] = $page;
       }
       // Redirect to the newly posted comment.
-      $redirect = array('node/' . $node->nid, array('query' => $query, 'fragment' => 'comment-' . $comment->cid));
+      $redirect = array('node/' . $node->nid, array('query' => $query, 'fragment' => 'comment-' . $comment->cid->value));
     }
     else {
-      watchdog('content', 'Comment: unauthorized comment submitted or comment submitted to a closed post %subject.', array('%subject' => $comment->subject), WATCHDOG_WARNING);
-      drupal_set_message(t('Comment: unauthorized comment submitted or comment submitted to a closed post %subject.', array('%subject' => $comment->subject)), 'error');
+      watchdog('content', 'Comment: unauthorized comment submitted or comment submitted to a closed post %subject.', array('%subject' => $comment->subject->value), WATCHDOG_WARNING);
+      drupal_set_message(t('Comment: unauthorized comment submitted or comment submitted to a closed post %subject.', array('%subject' => $comment->subject->value)), 'error');
       // Redirect the user to the node they are commenting on.
       $redirect = 'node/' . $node->nid;
     }
diff --git a/core/modules/comment/lib/Drupal/comment/CommentRenderController.php b/core/modules/comment/lib/Drupal/comment/CommentRenderController.php
index c614f8e..4bcbc39 100644
--- a/core/modules/comment/lib/Drupal/comment/CommentRenderController.php
+++ b/core/modules/comment/lib/Drupal/comment/CommentRenderController.php
@@ -73,7 +73,7 @@ protected function alterBuild(array &$build, EntityInterface $comment, $view_mod
       }
 
       // Add anchor for each comment.
-      $prefix .= "<a id=\"comment-$comment->cid\"></a>\n";
+      $prefix .= "<a id=\"comment-{$comment->cid->value}\"></a>\n";
       $build['#prefix'] = $prefix;
 
       // Close all open divs.
diff --git a/core/modules/comment/lib/Drupal/comment/CommentStorageController.php b/core/modules/comment/lib/Drupal/comment/CommentStorageController.php
index 4d447a5..69cf92a 100644
--- a/core/modules/comment/lib/Drupal/comment/CommentStorageController.php
+++ b/core/modules/comment/lib/Drupal/comment/CommentStorageController.php
@@ -8,7 +8,7 @@
 namespace Drupal\comment;
 
 use Drupal\Core\Entity\EntityInterface;
-use Drupal\Core\Entity\DatabaseStorageController;
+use Drupal\Core\Entity\DatabaseStorageControllerNG;
 use LogicException;
 
 /**
@@ -17,7 +17,7 @@
  * This extends the Drupal\Core\Entity\DatabaseStorageController class, adding
  * required special handling for comment entities.
  */
-class CommentStorageController extends DatabaseStorageController {
+class CommentStorageController extends DatabaseStorageControllerNG {
   /**
    * The thread for which a lock was acquired.
    */
@@ -33,6 +33,7 @@ protected function buildQuery($ids, $revision_id = FALSE) {
     $query->innerJoin('node', 'n', 'base.nid = n.nid');
     $query->addField('n', 'type', 'node_type');
     $query->innerJoin('users', 'u', 'base.uid = u.uid');
+    // @todo: Move this to computed properties.
     $query->addField('u', 'name', 'registered_name');
     $query->fields('u', array('uid', 'signature', 'signature_format', 'picture'));
     return $query;
@@ -41,15 +42,15 @@ protected function buildQuery($ids, $revision_id = FALSE) {
   /**
    * Overrides Drupal\Core\Entity\DatabaseStorageController::attachLoad().
    */
-  protected function attachLoad(&$comments, $load_revision = FALSE) {
-    // Set up standard comment properties.
-    foreach ($comments as $key => $comment) {
-      $comment->name = $comment->uid ? $comment->registered_name : $comment->name;
-      $comment->new = node_mark($comment->nid, $comment->changed);
-      $comment->node_type = 'comment_node_' . $comment->node_type;
-      $comments[$key] = $comment;
+  protected function attachLoad(&$records, $load_revision = FALSE) {
+    // Prepare standard comment properties.
+    foreach ($records as $key => $record) {
+      $record->name = $record->uid ? $record->registered_name : $record->name;
+      $record->new = node_mark($record->nid, $record->changed);
+      $record->node_type = 'comment_node_' . $record->node_type;
+      $records[$key] = $record;
     }
-    parent::attachLoad($comments, $load_revision);
+    parent::attachLoad($records, $load_revision);
   }
 
   /**
@@ -61,20 +62,19 @@ protected function attachLoad(&$comments, $load_revision = FALSE) {
   protected function preSave(EntityInterface $comment) {
     global $user;
 
-    if (!isset($comment->status)) {
-      $comment->status = user_access('skip comment approval') ? COMMENT_PUBLISHED : COMMENT_NOT_PUBLISHED;
+    if (!isset($comment->status->value)) {
+      $comment->status->value = user_access('skip comment approval') ? COMMENT_PUBLISHED : COMMENT_NOT_PUBLISHED;
     }
     // Make sure we have a proper bundle name.
-    if (!isset($comment->node_type)) {
-      $node = node_load($comment->nid);
-      $comment->node_type = 'comment_node_' . $node->type;
+    if (!isset($comment->node_type->value)) {
+      $comment->node_type->value = 'comment_node_' . $comment->nid->entity->type;
     }
-    if (!$comment->cid) {
+    if ($comment->isNew()) {
       // Add the comment to database. This next section builds the thread field.
       // Also see the documentation for comment_view().
-      if (!empty($comment->thread)) {
+      if (!empty($comment->thread->value)) {
         // Allow calling code to set thread itself.
-        $thread = $comment->thread;
+        $thread = $comment->thread->value;
       }
       else {
         if ($this->threadLock) {
@@ -82,10 +82,10 @@ protected function preSave(EntityInterface $comment) {
           // is extended in a faulty manner.
           throw new LogicException('preSave is called again without calling postSave() or releaseThreadLock()');
         }
-        if ($comment->pid == 0) {
+        if ($comment->pid->value == 0) {
           // This is a comment with no parent comment (depth 0): we start
           // by retrieving the maximum thread level.
-          $max = db_query('SELECT MAX(thread) FROM {comment} WHERE nid = :nid', array(':nid' => $comment->nid))->fetchField();
+          $max = db_query('SELECT MAX(thread) FROM {comment} WHERE nid = :nid', array(':nid' => $comment->nid->value))->fetchField();
           // Strip the "/" from the end of the thread.
           $max = rtrim($max, '/');
           // We need to get the value at the correct depth.
@@ -98,14 +98,14 @@ protected function preSave(EntityInterface $comment) {
           // the thread value at the proper depth.
 
           // Get the parent comment:
-          $parent = comment_load($comment->pid);
+          $parent = $comment->pid->entity;
           // Strip the "/" from the end of the parent thread.
-          $parent->thread = (string) rtrim((string) $parent->thread, '/');
-          $prefix = $parent->thread . '.';
+          $parent->thread->value = (string) rtrim((string) $parent->thread->value, '/');
+          $prefix = $parent->thread->value . '.';
           // Get the max value in *this* thread.
           $max = db_query("SELECT MAX(thread) FROM {comment} WHERE thread LIKE :thread AND nid = :nid", array(
-            ':thread' => $parent->thread . '.%',
-            ':nid' => $comment->nid,
+            ':thread' => $parent->thread->value . '.%',
+            ':nid' => $comment->nid->value,
           ))->fetchField();
 
           if ($max == '') {
@@ -119,7 +119,7 @@ protected function preSave(EntityInterface $comment) {
             $max = rtrim($max, '/');
             // Get the value at the correct depth.
             $parts = explode('.', $max);
-            $parent_depth = count(explode('.', $parent->thread));
+            $parent_depth = count(explode('.', $parent->thread->value));
             $n = comment_alphadecimal_to_int($parts[$parent_depth]);
           }
         }
@@ -128,23 +128,23 @@ protected function preSave(EntityInterface $comment) {
         // has the lock, just move to the next integer.
         do {
           $thread = $prefix . comment_int_to_alphadecimal(++$n) . '/';
-        } while (!lock()->acquire("comment:$comment->nid:$thread"));
+        } while (!lock()->acquire("comment:{$comment->nid->value}:$thread"));
         $this->threadLock = $thread;
       }
-      if (empty($comment->created)) {
-        $comment->created = REQUEST_TIME;
+      if (empty($comment->created->value)) {
+        $comment->created->value = REQUEST_TIME;
       }
-      if (empty($comment->changed)) {
-        $comment->changed = $comment->created;
+      if (empty($comment->changed->value)) {
+        $comment->changed->value = $comment->created->value;
       }
       // We test the value with '===' because we need to modify anonymous
       // users as well.
-      if ($comment->uid === $user->uid && isset($user->name)) {
-        $comment->name = $user->name;
+      if ($comment->uid->value === $user->uid && isset($user->name)) {
+        $comment->name->value = $user->name;
       }
       // Add the values which aren't passed into the function.
-      $comment->thread = $thread;
-      $comment->hostname = ip_address();
+      $comment->thread->value = $thread;
+      $comment->hostname->value = ip_address();
     }
   }
 
@@ -154,8 +154,8 @@ protected function preSave(EntityInterface $comment) {
   protected function postSave(EntityInterface $comment, $update) {
     $this->releaseThreadLock();
     // Update the {node_comment_statistics} table prior to executing the hook.
-    $this->updateNodeStatistics($comment->nid);
-    if ($comment->status == COMMENT_PUBLISHED) {
+    $this->updateNodeStatistics($comment->nid->value);
+    if ($comment->status->value == COMMENT_PUBLISHED) {
       module_invoke_all('comment_publish', $comment);
     }
   }
@@ -172,7 +172,7 @@ protected function postDelete($comments) {
     comment_delete_multiple($child_cids);
 
     foreach ($comments as $comment) {
-      $this->updateNodeStatistics($comment->nid);
+      $this->updateNodeStatistics($comment->nid->value);
     }
   }
 
@@ -246,4 +246,98 @@ protected function releaseThreadLock() {
       $this->threadLock = '';
     }
   }
+
+  /**
+   * Implements \Drupal\Core\Entity\DataBaseStorageControllerNG::basePropertyDefinitions().
+   */
+  public function basePropertyDefinitions() {
+    $properties['cid'] = array(
+      'label' => t('ID'),
+      'description' => t('The comment ID.'),
+      'type' => 'integer_item',
+      'read-only' => TRUE,
+    );
+    $properties['uuid'] = array(
+      'label' => t('UUID'),
+      'description' => t('The comment UUID.'),
+      'type' => 'string_item',
+    );
+    $properties['langcode'] = array(
+      'label' => t('Language code'),
+      'description' => t('The comment language code.'),
+      'type' => 'language_item',
+    );
+    $properties['nid'] = array(
+      'label' => t('Node ID'),
+      'description' => t('The ID of the node of which this comment is a reply.'),
+      'type' => 'entityreference_item',
+      'settings' => array('entity type' => 'node'),
+      'required' => TRUE,
+    );
+    $properties['pid'] = array(
+      'label' => t('Parent ID'),
+      'description' => t('The parent comment ID if this is a reply to a comment.'),
+      'type' => 'entityreference_item',
+      'settings' => array('entity type' => 'comment'),
+    );
+    $properties['subject'] = array(
+      'label' => t('Subject'),
+      'description' => t('The comment title or subject.'),
+      'type' => 'string_item',
+    );
+    $properties['uid'] = array(
+      'label' => t('User ID'),
+      'description' => t('The user ID of the comment author.'),
+      'type' => 'entityreference_item',
+      'settings' => array('entity type' => 'user'),
+    );
+    $properties['name'] = array(
+      'label' => t('Name'),
+      'description' => t("The comment author's name."),
+      'type' => 'string_item',
+    );
+    $properties['mail'] = array(
+      'label' => t('e-mail'),
+      'description' => t("The comment author's e-mail address."),
+      'type' => 'string_item',
+    );
+    $properties['homepage'] = array(
+      'label' => t('Homepage'),
+      'description' => t("The comment author's home page address."),
+      'type' => 'string_item',
+    );
+    $properties['hostname'] = array(
+      'label' => t('Hostname'),
+      'description' => t("The comment author's hostname."),
+      'type' => 'string_item',
+    );
+    $properties['created'] = array(
+      'label' => t('Created'),
+      'description' => t('The time that the comment was created.'),
+      'type' => 'date_item',
+    );
+    $properties['changed'] = array(
+      'label' => t('Changed'),
+      'description' => t('The time that the comment was last edited.'),
+      'type' => 'date_item',
+    );
+    $properties['status'] = array(
+      'label' => t('Publishing status'),
+      'description' => t('A boolean indicating whether the comment is published.'),
+      'type' => 'boolean_item',
+    );
+    $properties['thread'] = array(
+      'label' => t('Thread place'),
+      'description' => t("The alphadecimal representation of the comment's place in a thread, consisting of a base 36 string prefixed by an integer indicating its length."),
+      'type' => 'string_item',
+    );
+    $properties['node_type'] = array(
+      // @todo: The bundle property should be stored so it's queryable.
+      'label' => t('Node type'),
+      'description' => t("The comment node type."),
+      'type' => 'string_item',
+      'queryable' => FALSE,
+    );
+    return $properties;
+  }
 }
diff --git a/core/modules/comment/lib/Drupal/comment/Tests/CommentActionsTest.php b/core/modules/comment/lib/Drupal/comment/Tests/CommentActionsTest.php
index 4a2e9ca..ad21f84 100644
--- a/core/modules/comment/lib/Drupal/comment/Tests/CommentActionsTest.php
+++ b/core/modules/comment/lib/Drupal/comment/Tests/CommentActionsTest.php
@@ -39,24 +39,24 @@ function testCommentPublishUnpublishActions() {
 
     // Unpublish a comment (direct form: doesn't actually save the comment).
     comment_unpublish_action($comment);
-    $this->assertEqual($comment->status, COMMENT_NOT_PUBLISHED, 'Comment was unpublished');
+    $this->assertEqual($comment->status->valeu, COMMENT_NOT_PUBLISHED, 'Comment was unpublished');
     $this->assertWatchdogMessage('Unpublished comment %subject.', array('%subject' => $subject), 'Found watchdog message');
     $this->clearWatchdog();
 
     // Unpublish a comment (indirect form: modify the comment in the database).
-    comment_unpublish_action(NULL, array('cid' => $comment->cid));
-    $this->assertEqual(comment_load($comment->cid)->status, COMMENT_NOT_PUBLISHED, 'Comment was unpublished');
+    comment_unpublish_action(NULL, array('cid' => $comment->cid->value));
+    $this->assertEqual(comment_load($comment->cid->value)->status, COMMENT_NOT_PUBLISHED, 'Comment was unpublished');
     $this->assertWatchdogMessage('Unpublished comment %subject.', array('%subject' => $subject), 'Found watchdog message');
 
     // Publish a comment (direct form: doesn't actually save the comment).
     comment_publish_action($comment);
-    $this->assertEqual($comment->status, COMMENT_PUBLISHED, 'Comment was published');
+    $this->assertEqual($comment->status->value, COMMENT_PUBLISHED, 'Comment was published');
     $this->assertWatchdogMessage('Published comment %subject.', array('%subject' => $subject), 'Found watchdog message');
     $this->clearWatchdog();
 
     // Publish a comment (indirect form: modify the comment in the database).
-    comment_publish_action(NULL, array('cid' => $comment->cid));
-    $this->assertEqual(comment_load($comment->cid)->status, COMMENT_PUBLISHED, 'Comment was published');
+    comment_publish_action(NULL, array('cid' => $comment->cid->value));
+    $this->assertEqual(comment_load($comment->cid->value)->status, COMMENT_PUBLISHED, 'Comment was published');
     $this->assertWatchdogMessage('Published comment %subject.', array('%subject' => $subject), 'Found watchdog message');
     $this->clearWatchdog();
   }
diff --git a/core/modules/comment/lib/Drupal/comment/Tests/CommentInterfaceTest.php b/core/modules/comment/lib/Drupal/comment/Tests/CommentInterfaceTest.php
index 1070107..a00be4f 100644
--- a/core/modules/comment/lib/Drupal/comment/Tests/CommentInterfaceTest.php
+++ b/core/modules/comment/lib/Drupal/comment/Tests/CommentInterfaceTest.php
@@ -70,7 +70,7 @@ function testCommentInterface() {
     $this->drupalGet('comment/' . $comment->id . '/edit');
     $comment = $this->postComment(NULL, $comment->comment, $comment->subject, array('name' => ''));
     $comment_loaded = comment_load($comment->id);
-    $this->assertTrue(empty($comment_loaded->name) && $comment_loaded->uid == 0, 'Comment author successfully changed to anonymous.');
+    $this->assertTrue(empty($comment_loaded->name->value) && $comment_loaded->uid == 0, 'Comment author successfully changed to anonymous.');
 
     // Test changing the comment author to an unverified user.
     $random_name = $this->randomName();
@@ -83,7 +83,7 @@ function testCommentInterface() {
     $this->drupalGet('comment/' . $comment->id . '/edit');
     $comment = $this->postComment(NULL, $comment->comment, $comment->subject, array('name' => $this->web_user->name));
     $comment_loaded = comment_load($comment->id);
-    $this->assertTrue($comment_loaded->name == $this->web_user->name && $comment_loaded->uid == $this->web_user->uid, 'Comment author successfully changed to a registered user.');
+    $this->assertTrue($comment_loaded->name->value == $this->web_user->name && $comment_loaded->uid == $this->web_user->uid, 'Comment author successfully changed to a registered user.');
 
     $this->drupalLogout();
 
@@ -96,8 +96,8 @@ function testCommentInterface() {
     $reply = $this->postComment(NULL, $this->randomName(), '', TRUE);
     $reply_loaded = comment_load($reply->id);
     $this->assertTrue($this->commentExists($reply, TRUE), 'Reply found.');
-    $this->assertEqual($comment->id, $reply_loaded->pid, 'Pid of a reply to a comment is set correctly.');
-    $this->assertEqual(rtrim($comment_loaded->thread, '/') . '.00/', $reply_loaded->thread, 'Thread of reply grows correctly.');
+    $this->assertEqual($comment->id, $reply_loaded->pid->value, 'Pid of a reply to a comment is set correctly.');
+    $this->assertEqual(rtrim($comment_loaded->thread->value, '/') . '.00/', $reply_loaded->thread->value, 'Thread of reply grows correctly.');
 
     // Second reply to comment #3 creating comment #4.
     $this->drupalGet('comment/reply/' . $this->node->nid . '/' . $comment->id);
@@ -106,7 +106,7 @@ function testCommentInterface() {
     $reply = $this->postComment(NULL, $this->randomName(), $this->randomName(), TRUE);
     $reply_loaded = comment_load($reply->id);
     $this->assertTrue($this->commentExists($reply, TRUE), 'Second reply found.');
-    $this->assertEqual(rtrim($comment_loaded->thread, '/') . '.01/', $reply_loaded->thread, 'Thread of second reply grows correctly.');
+    $this->assertEqual(rtrim($comment_loaded->thread->value, '/') . '.01/', $reply_loaded->thread->value, 'Thread of second reply grows correctly.');
 
     // Edit reply.
     $this->drupalGet('comment/' . $reply->id . '/edit');
diff --git a/core/modules/comment/lib/Drupal/comment/Tests/CommentPreviewTest.php b/core/modules/comment/lib/Drupal/comment/Tests/CommentPreviewTest.php
index 44a38d5..1984101 100644
--- a/core/modules/comment/lib/Drupal/comment/Tests/CommentPreviewTest.php
+++ b/core/modules/comment/lib/Drupal/comment/Tests/CommentPreviewTest.php
@@ -131,10 +131,10 @@ function testCommentEditPreviewSave() {
 
     // Check that the saved comment is still correct.
     $comment_loaded = comment_load($comment->id);
-    $this->assertEqual($comment_loaded->subject, $edit['subject'], 'Subject loaded.');
-    $this->assertEqual($comment_loaded->comment_body[$langcode][0]['value'], $edit['comment_body[' . $langcode . '][0][value]'], 'Comment body loaded.');
-    $this->assertEqual($comment_loaded->name, $edit['name'], 'Name loaded.');
-    $this->assertEqual($comment_loaded->created, $raw_date, 'Date loaded.');
+    $this->assertEqual($comment_loaded->subject->value, $edit['subject'], 'Subject loaded.');
+    $this->assertEqual($comment_loaded->comment_body->value, $edit['comment_body[' . $langcode . '][0][value]'], 'Comment body loaded.');
+    $this->assertEqual($comment_loaded->name->value, $edit['name'], 'Name loaded.');
+    $this->assertEqual($comment_loaded->created->value, $raw_date, 'Date loaded.');
 
   }
 
diff --git a/core/modules/comment/lib/Drupal/comment/Tests/CommentTestBase.php b/core/modules/comment/lib/Drupal/comment/Tests/CommentTestBase.php
index 37a8b47..6387217 100644
--- a/core/modules/comment/lib/Drupal/comment/Tests/CommentTestBase.php
+++ b/core/modules/comment/lib/Drupal/comment/Tests/CommentTestBase.php
@@ -164,8 +164,8 @@ function commentExists(Comment $comment = NULL, $reply = FALSE) {
     if ($comment) {
       $regex = '/' . ($reply ? '<div class="indented">(.*?)' : '');
       $regex .= '<a id="comment-' . $comment->id . '"(.*?)'; // Comment anchor.
-      $regex .= $comment->subject . '(.*?)'; // Match subject.
-      $regex .= $comment->comment . '(.*?)'; // Match comment.
+      $regex .= $comment->subject->value . '(.*?)'; // Match subject.
+      $regex .= $comment->comment->value . '(.*?)'; // Match comment.
       $regex .= '/s';
 
       return (boolean)preg_match($regex, $this->drupalGetContent());
diff --git a/core/modules/comment/lib/Drupal/comment/Tests/CommentThreadingTest.php b/core/modules/comment/lib/Drupal/comment/Tests/CommentThreadingTest.php
index 7f4edd5..cd2e0e9 100644
--- a/core/modules/comment/lib/Drupal/comment/Tests/CommentThreadingTest.php
+++ b/core/modules/comment/lib/Drupal/comment/Tests/CommentThreadingTest.php
@@ -43,7 +43,7 @@ function testCommentThreading() {
     $comment = $this->postComment($this->node, $comment_text, $subject_text, TRUE);
     $comment_loaded = comment_load($comment->id);
     $this->assertTrue($this->commentExists($comment), 'Comment #1. Comment found.');
-    $this->assertEqual($comment_loaded->thread, '01/');
+    $this->assertEqual($comment_loaded->thread->value, '01/');
 
     // Reply to comment #1 creating comment #2.
     $this->drupalLogin($this->web_user);
@@ -75,7 +75,7 @@ function testCommentThreading() {
     $comment = $this->postComment($this->node, $comment_text, $subject_text, TRUE);
     $comment_loaded = comment_load($comment->id);
     $this->assertTrue($this->commentExists($comment), 'Comment #5. Second comment found.');
-    $this->assertEqual($comment_loaded->thread, '02/');
+    $this->assertEqual($comment_loaded->thread->value, '02/');
 
     // Reply to comment #5 creating comment #6.
     $this->drupalLogin($this->web_user);
diff --git a/core/modules/comment/lib/Drupal/comment/Tests/CommentTokenReplaceTest.php b/core/modules/comment/lib/Drupal/comment/Tests/CommentTokenReplaceTest.php
index 34674e8..9fa0c60 100644
--- a/core/modules/comment/lib/Drupal/comment/Tests/CommentTokenReplaceTest.php
+++ b/core/modules/comment/lib/Drupal/comment/Tests/CommentTokenReplaceTest.php
@@ -42,30 +42,30 @@ function testCommentTokenReplacement() {
     $this->drupalGet('comment/reply/' . $node->nid . '/' . $parent_comment->id);
     $child_comment = $this->postComment(NULL, $this->randomName(), $this->randomName());
     $comment = comment_load($child_comment->id);
-    $comment->homepage = 'http://example.org/';
+    $comment->homepage->value = 'http://example.org/';
 
     // Add HTML to ensure that sanitation of some fields tested directly.
-    $comment->subject = '<blink>Blinking Comment</blink>';
+    $comment->subject->value = '<blink>Blinking Comment</blink>';
     $instance = field_info_instance('comment', 'body', 'comment_body');
 
     // Generate and test sanitized tokens.
     $tests = array();
-    $tests['[comment:cid]'] = $comment->cid;
-    $tests['[comment:hostname]'] = check_plain($comment->hostname);
-    $tests['[comment:name]'] = filter_xss($comment->name);
+    $tests['[comment:cid]'] = $comment->cid->value;
+    $tests['[comment:hostname]'] = check_plain($comment->hostname->value);
+    $tests['[comment:name]'] = filter_xss($comment->name->value);
     $tests['[comment:mail]'] = check_plain($this->admin_user->mail);
-    $tests['[comment:homepage]'] = check_url($comment->homepage);
-    $tests['[comment:title]'] = filter_xss($comment->subject);
-    $tests['[comment:body]'] = _text_sanitize($instance, LANGUAGE_NOT_SPECIFIED, $comment->comment_body[LANGUAGE_NOT_SPECIFIED][0], 'value');
-    $tests['[comment:url]'] = url('comment/' . $comment->cid, $url_options + array('fragment' => 'comment-' . $comment->cid));
-    $tests['[comment:edit-url]'] = url('comment/' . $comment->cid . '/edit', $url_options);
-    $tests['[comment:created:since]'] = format_interval(REQUEST_TIME - $comment->created, 2, $language_interface->langcode);
-    $tests['[comment:changed:since]'] = format_interval(REQUEST_TIME - $comment->changed, 2, $language_interface->langcode);
-    $tests['[comment:parent:cid]'] = $comment->pid;
+    $tests['[comment:homepage]'] = check_url($comment->homepage->value);
+    $tests['[comment:title]'] = filter_xss($comment->subject->value);
+    $tests['[comment:body]'] = $comment->comment_body->processed;
+    $tests['[comment:url]'] = url('comment/' . $comment->cid->value, $url_options + array('fragment' => 'comment-' . $comment->cid->value));
+    $tests['[comment:edit-url]'] = url('comment/' . $comment->cid->value . '/edit', $url_options);
+    $tests['[comment:created:since]'] = format_interval(REQUEST_TIME - $comment->created->value->getTimestamp(), 2, $language_interface->langcode);
+    $tests['[comment:changed:since]'] = format_interval(REQUEST_TIME - $comment->changed->value->getTimestamp(), 2, $language_interface->langcode);
+    $tests['[comment:parent:cid]'] = $comment->pid->value;
     $tests['[comment:parent:title]'] = check_plain($parent_comment->subject);
-    $tests['[comment:node:nid]'] = $comment->nid;
+    $tests['[comment:node:nid]'] = $comment->nid->value;
     $tests['[comment:node:title]'] = check_plain($node->title);
-    $tests['[comment:author:uid]'] = $comment->uid;
+    $tests['[comment:author:uid]'] = $comment->uid->value;
     $tests['[comment:author:name]'] = check_plain($this->admin_user->name);
 
     // Test to make sure that we generated something for each token.
@@ -77,13 +77,13 @@ function testCommentTokenReplacement() {
     }
 
     // Generate and test unsanitized tokens.
-    $tests['[comment:hostname]'] = $comment->hostname;
-    $tests['[comment:name]'] = $comment->name;
+    $tests['[comment:hostname]'] = $comment->hostname->value;
+    $tests['[comment:name]'] = $comment->name->value;
     $tests['[comment:mail]'] = $this->admin_user->mail;
-    $tests['[comment:homepage]'] = $comment->homepage;
-    $tests['[comment:title]'] = $comment->subject;
-    $tests['[comment:body]'] = $comment->comment_body[LANGUAGE_NOT_SPECIFIED][0]['value'];
-    $tests['[comment:parent:title]'] = $parent_comment->subject;
+    $tests['[comment:homepage]'] = $comment->homepage->value;
+    $tests['[comment:title]'] = $comment->subject->value;
+    $tests['[comment:body]'] = $comment->comment_body->value;
+    $tests['[comment:parent:title]'] = $parent_comment->subject->value;
     $tests['[comment:node:title]'] = $node->title;
     $tests['[comment:author:name]'] = $this->admin_user->name;
 
diff --git a/core/modules/field/field.attach.inc b/core/modules/field/field.attach.inc
index d267546..18b2f28 100644
--- a/core/modules/field/field.attach.inc
+++ b/core/modules/field/field.attach.inc
@@ -1364,6 +1364,13 @@ function field_attach_prepare_view($entity_type, $entities, $view_mode, $langcod
       // Add this entity to the items to be prepared.
       $prepare[$id] = $entity;
 
+      // Enable compatibility mode if necessary.
+      // @todo: Remove this once all entity types have been converted to the
+      // new property API.
+      if ($entity instanceof \Drupal\Core\Entity\EntityNG) {
+        $entity->setCompatibilityMode(TRUE);
+      }
+
       // Determine the actual language code to display for each field, given the
       // language codes available in the field data.
       $options['langcode'][$id] = field_language($entity_type, $entity, NULL, $langcode);
@@ -1378,6 +1385,15 @@ function field_attach_prepare_view($entity_type, $entities, $view_mode, $langcod
   _field_invoke_multiple('prepare_view', $entity_type, $prepare, $null, $null, $options);
   // Then let the formatters do their own specific massaging.
   field_invoke_method_multiple('prepareView', _field_invoke_formatter_target($view_mode), $prepare, $view_mode, $null, $options);
+
+  // Disable compatibility mode if enabled previously.
+  // @todo: Remove this once all entity types have been converted to the
+  // new property API.
+  foreach ($prepare as $entity) {
+    if ($entity instanceof \Drupal\Core\Entity\EntityNG) {
+      $entity->setCompatibilityMode(FALSE);
+    }
+  }
 }
 
 /**
diff --git a/core/modules/file/lib/Drupal/file/Tests/FileFieldWidgetTest.php b/core/modules/file/lib/Drupal/file/Tests/FileFieldWidgetTest.php
index 0bb8866..bfc3e9c 100644
--- a/core/modules/file/lib/Drupal/file/Tests/FileFieldWidgetTest.php
+++ b/core/modules/file/lib/Drupal/file/Tests/FileFieldWidgetTest.php
@@ -290,14 +290,14 @@ function testPrivateFileComment() {
     $comment_file = file_load($comment->{'field_' . $name}[LANGUAGE_NOT_SPECIFIED][0]['fid']);
     $this->assertFileExists($comment_file, t('New file saved to disk on node creation.'));
     // Test authenticated file download.
-    $url = file_create_url($comment_file->uri);
+    $url = file_create_url($comment_file->uri->value);
     $this->assertNotEqual($url, NULL, t('Confirmed that the URL is valid'));
-    $this->drupalGet(file_create_url($comment_file->uri));
+    $this->drupalGet(file_create_url($comment_file->uri->value));
     $this->assertResponse(200, t('Confirmed that the generated URL is correct by downloading the shipped file.'));
 
     // Test anonymous file download.
     $this->drupalLogout();
-    $this->drupalGet(file_create_url($comment_file->uri));
+    $this->drupalGet(file_create_url($comment_file->uri->value));
     $this->assertResponse(403, t('Confirmed that access is denied for the file without the needed permission.'));
 
     // Unpublishes node.
@@ -309,7 +309,7 @@ function testPrivateFileComment() {
 
     // Ensures normal user can no longer download the file.
     $this->drupalLogin($user);
-    $this->drupalGet(file_create_url($comment_file->uri));
+    $this->drupalGet(file_create_url($comment_file->uri->value));
     $this->assertResponse(403, t('Confirmed that access is denied for the file without the needed permission.'));
   }
 
diff --git a/core/modules/forum/forum.module b/core/modules/forum/forum.module
index af2daa9..2855a97 100644
--- a/core/modules/forum/forum.module
+++ b/core/modules/forum/forum.module
@@ -491,7 +491,7 @@ function forum_taxonomy_term_delete(Term $term) {
  * comment_save() calls hook_comment_publish() for all published comments.
  */
 function forum_comment_publish($comment) {
-  _forum_update_forum_index($comment->nid);
+  _forum_update_forum_index($comment->nid->value);
 }
 
 /**
@@ -503,8 +503,8 @@ function forum_comment_publish($comment) {
 function forum_comment_update($comment) {
   // comment_save() calls hook_comment_publish() for all published comments,
   // so we need to handle all other values here.
-  if (!$comment->status) {
-    _forum_update_forum_index($comment->nid);
+  if (!$comment->status->value) {
+    _forum_update_forum_index($comment->nid->value);
   }
 }
 
@@ -512,14 +512,14 @@ function forum_comment_update($comment) {
  * Implements hook_comment_unpublish().
  */
 function forum_comment_unpublish($comment) {
-  _forum_update_forum_index($comment->nid);
+  _forum_update_forum_index($comment->nid->value);
 }
 
 /**
  * Implements hook_comment_delete().
  */
 function forum_comment_delete($comment) {
-  _forum_update_forum_index($comment->nid);
+  _forum_update_forum_index($comment->nid->value);
 }
 
 /**
diff --git a/core/modules/node/node.api.php b/core/modules/node/node.api.php
index 113cc3d..474ac6c 100644
--- a/core/modules/node/node.api.php
+++ b/core/modules/node/node.api.php
@@ -757,7 +757,7 @@ function hook_node_update_index(Drupal\node\Node $node, $langcode) {
   $text = '';
   $comments = db_query('SELECT subject, comment, format FROM {comment} WHERE nid = :nid AND status = :status', array(':nid' => $node->nid, ':status' => COMMENT_PUBLISHED));
   foreach ($comments as $comment) {
-    $text .= '<h2>' . check_plain($comment->subject) . '</h2>' . check_markup($comment->comment, $comment->format, '', TRUE);
+    $text .= '<h2>' . check_plain($comment->subject->value) . '</h2>' . check_markup($comment->comment->value, $comment->format->value, '', TRUE);
   }
   return $text;
 }
diff --git a/core/modules/rdf/lib/Drupal/rdf/Tests/CommentAttributesTest.php b/core/modules/rdf/lib/Drupal/rdf/Tests/CommentAttributesTest.php
index fc883cb..09287f1 100644
--- a/core/modules/rdf/lib/Drupal/rdf/Tests/CommentAttributesTest.php
+++ b/core/modules/rdf/lib/Drupal/rdf/Tests/CommentAttributesTest.php
@@ -181,7 +181,7 @@ function _testBasicCommentRdfaMarkup($comment, $account = array()) {
     $comment_container = $this->xpath('//div[contains(@class, "comment") and contains(@typeof, "sioct:Comment")]');
     $this->assertTrue(!empty($comment_container), 'Comment RDF type for comment found.');
     $comment_title = $this->xpath('//div[contains(@class, "comment") and contains(@typeof, "sioct:Comment")]//h3[@property="dc:title"]');
-    $this->assertEqual((string) $comment_title[0]->a, $comment->subject, 'RDFa markup for the comment title found.');
+    $this->assertEqual((string) $comment_title[0]->a, $comment->subject->value, 'RDFa markup for the comment title found.');
     $comment_date = $this->xpath('//div[contains(@class, "comment") and contains(@typeof, "sioct:Comment")]//*[contains(@property, "dc:date") and contains(@property, "dc:created")]');
     $this->assertTrue(!empty($comment_date), 'RDFa markup for the date of the comment found.');
     // The author tag can be either a or span
@@ -189,6 +189,6 @@ function _testBasicCommentRdfaMarkup($comment, $account = array()) {
     $name = empty($account["name"]) ? $this->web_user->name : $account["name"] . " (not verified)";
     $this->assertEqual((string) $comment_author[0], $name, 'RDFa markup for the comment author found.');
     $comment_body = $this->xpath('//div[contains(@class, "comment") and contains(@typeof, "sioct:Comment")]//div[@class="content"]//div[contains(@class, "comment-body")]//div[@property="content:encoded"]');
-    $this->assertEqual((string) $comment_body[0]->p, $comment->comment, 'RDFa markup for the comment body found.');
+    $this->assertEqual((string) $comment_body[0]->p, $comment->comment->value, 'RDFa markup for the comment body found.');
   }
 }
diff --git a/core/modules/rdf/rdf.module b/core/modules/rdf/rdf.module
index 782c06f..1a622cd 100644
--- a/core/modules/rdf/rdf.module
+++ b/core/modules/rdf/rdf.module
@@ -428,10 +428,10 @@ function rdf_comment_load($comments) {
     // Pages with many comments can show poor performance. This information
     // isn't needed until rdf_preprocess_comment() is called, but set it here
     // to optimize performance for websites that implement an entity cache.
-    $comment->rdf_data['date'] = rdf_rdfa_attributes($comment->rdf_mapping['created'], $comment->created);
-    $comment->rdf_data['nid_uri'] = url('node/' . $comment->nid);
-    if ($comment->pid) {
-      $comment->rdf_data['pid_uri'] = url('comment/' . $comment->pid, array('fragment' => 'comment-' . $comment->pid));
+    $comment->rdf_data['date'] = rdf_rdfa_attributes($comment->rdf_mapping['created'], $comment->created->value->getTimestamp());
+    $comment->rdf_data['nid_uri'] = url('node/' . $comment->nid->value);
+    if ($comment->pid->value) {
+      $comment->rdf_data['pid_uri'] = url('comment/' . $comment->pid->value, array('fragment' => 'comment-' . $comment->pid->value));
     }
   }
 }
@@ -754,7 +754,7 @@ function rdf_preprocess_comment(&$variables) {
     $variables['rdf_metadata_attributes'][] = $parent_node_attributes;
 
     // Adds the relation to parent comment, if it exists.
-    if ($comment->pid != 0) {
+    if ($comment->pid->value != 0) {
       $parent_comment_attributes['rel'] = $comment->rdf_mapping['pid']['predicates'];
       // The parent comment URI is precomputed as part of the rdf_data so that
       // it can be cached as part of the entity.
diff --git a/core/modules/search/search.module b/core/modules/search/search.module
index 315ae7a..7be3ae7 100644
--- a/core/modules/search/search.module
+++ b/core/modules/search/search.module
@@ -832,7 +832,7 @@ function search_node_update(Node $node) {
  */
 function search_comment_insert($comment) {
   // Reindex the node when comments are added.
-  search_touch_node($comment->nid);
+  search_touch_node($comment->nid->value);
 }
 
 /**
@@ -840,7 +840,7 @@ function search_comment_insert($comment) {
  */
 function search_comment_update($comment) {
   // Reindex the node when comments are changed.
-  search_touch_node($comment->nid);
+  search_touch_node($comment->nid->value);
 }
 
 /**
@@ -848,7 +848,7 @@ function search_comment_update($comment) {
  */
 function search_comment_delete($comment) {
   // Reindex the node when comments are deleted.
-  search_touch_node($comment->nid);
+  search_touch_node($comment->nid->value);
 }
 
 /**
@@ -856,7 +856,7 @@ function search_comment_delete($comment) {
  */
 function search_comment_publish($comment) {
   // Reindex the node when comments are published.
-  search_touch_node($comment->nid);
+  search_touch_node($comment->nid->value);
 }
 
 /**
@@ -864,7 +864,7 @@ function search_comment_publish($comment) {
  */
 function search_comment_unpublish($comment) {
   // Reindex the node when comments are unpublished.
-  search_touch_node($comment->nid);
+  search_touch_node($comment->nid->value);
 }
 
 /**
diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityCrudHookTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityCrudHookTest.php
index 4afb574..38e35bc 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityCrudHookTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityCrudHookTest.php
@@ -107,7 +107,7 @@ public function testCommentHooks() {
     ));
 
     $_SESSION['entity_crud_hook_test'] = array();
-    $comment = comment_load($comment->cid);
+    $comment = comment_load($comment->cid->value);
 
     $this->assertHookMessageOrder(array(
       'entity_crud_hook_test_entity_load called for type comment',
@@ -115,7 +115,7 @@ public function testCommentHooks() {
     ));
 
     $_SESSION['entity_crud_hook_test'] = array();
-    $comment->subject = 'New subject';
+    $comment->subject->value = 'New subject';
     comment_save($comment);
 
     $this->assertHookMessageOrder(array(
@@ -126,7 +126,7 @@ public function testCommentHooks() {
     ));
 
     $_SESSION['entity_crud_hook_test'] = array();
-    comment_delete($comment->cid);
+    comment_delete($comment->cid->value);
 
     $this->assertHookMessageOrder(array(
       'entity_crud_hook_test_comment_predelete called',
diff --git a/core/modules/system/lib/Drupal/system/Tests/Upgrade/LanguageUpgradePathTest.php b/core/modules/system/lib/Drupal/system/Tests/Upgrade/LanguageUpgradePathTest.php
index 65c30de..ca32069 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Upgrade/LanguageUpgradePathTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Upgrade/LanguageUpgradePathTest.php
@@ -53,7 +53,7 @@ public function testLanguageUpgrade() {
 
     // Directly check the comment language property on the first comment.
     $comment = db_query('SELECT * FROM {comment} WHERE cid = :cid', array(':cid' => 1))->fetchObject();
-    $this->assertTrue($comment->langcode == 'und', t('Comment 1 language code found.'));
+    $this->assertTrue($comment->langcode->value == 'und', t('Comment 1 language code found.'));
 
     // Ensure that the language switcher has been correctly upgraded. We need to
     // assert the expected HTML id because the block might appear even if the
diff --git a/core/modules/tracker/tracker.module b/core/modules/tracker/tracker.module
index 7060a87..fef4ad0 100644
--- a/core/modules/tracker/tracker.module
+++ b/core/modules/tracker/tracker.module
@@ -228,8 +228,8 @@ function tracker_node_predelete(Node $node, $arg = 0) {
 function tracker_comment_update($comment) {
   // comment_save() calls hook_comment_publish() for all published comments
   // so we need to handle all other values here.
-  if ($comment->status != COMMENT_PUBLISHED) {
-    _tracker_remove($comment->nid, $comment->uid, $comment->changed);
+  if ($comment->status->value != COMMENT_PUBLISHED) {
+    _tracker_remove($comment->nid->value, $comment->uid->value, $comment->changed->value->getTimestamp());
   }
 }
 
@@ -240,21 +240,21 @@ function tracker_comment_update($comment) {
  * comment_save() calls hook_comment_publish() for all published comments.
  */
 function tracker_comment_publish($comment) {
-  _tracker_add($comment->nid, $comment->uid, $comment->changed);
+  _tracker_add($comment->nid->value, $comment->uid->value, $comment->changed->value->getTimestamp());
 }
 
 /**
  * Implements hook_comment_unpublish().
  */
 function tracker_comment_unpublish($comment) {
-  _tracker_remove($comment->nid, $comment->uid, $comment->changed);
+  _tracker_remove($comment->nid->value, $comment->uid->value, $comment->changed->value->getTimestamp());
 }
 
 /**
  * Implements hook_comment_delete().
  */
 function tracker_comment_delete($comment) {
-  _tracker_remove($comment->nid, $comment->uid, $comment->changed);
+  _tracker_remove($comment->nid->value, $comment->uid->value, $comment->changed->value->getTimestamp());
 }
 
 /**
diff --git a/core/modules/user/lib/Drupal/user/Tests/UserCancelTest.php b/core/modules/user/lib/Drupal/user/Tests/UserCancelTest.php
index 8b51fe0..935b26d 100644
--- a/core/modules/user/lib/Drupal/user/Tests/UserCancelTest.php
+++ b/core/modules/user/lib/Drupal/user/Tests/UserCancelTest.php
@@ -299,7 +299,7 @@ function testUserDelete() {
     $this->assertText(t('Your comment has been posted.'));
     $comments = entity_load_multiple_by_properties('comment', array('subject' => $edit['subject']));
     $comment = reset($comments);
-    $this->assertTrue($comment->cid, 'Comment found.');
+    $this->assertTrue($comment->cid->value, 'Comment found.');
 
     // Create a node with two revisions, the initial one belonging to the
     // cancelling user.
@@ -329,7 +329,7 @@ function testUserDelete() {
     $this->assertFalse(node_load($node->nid, TRUE), 'Node of the user has been deleted.');
     $this->assertFalse(node_revision_load($revision), 'Node revision of the user has been deleted.');
     $this->assertTrue(node_load($revision_node->nid, TRUE), "Current revision of the user's node was not deleted.");
-    $this->assertFalse(comment_load($comment->cid), 'Comment of the user has been deleted.');
+    $this->assertFalse(comment_load($comment->cid->value), 'Comment of the user has been deleted.');
 
     // Confirm that user is logged out.
     $this->assertNoText($account->name, 'Logged out.');
