diff --git a/core/modules/node/content_types.inc b/core/modules/node/content_types.inc
index e838460..c4933fd 100644
--- a/core/modules/node/content_types.inc
+++ b/core/modules/node/content_types.inc
@@ -75,27 +75,20 @@ function node_overview_types() {
 }
 
 /**
- * Returns HTML for a node type description for the content type admin page.
+ * Prepares variables for node type description templates.
  *
- * @param $variables
+ * Default template: node-admin-overview.html.twig.
+ *
+ * @param array $variables
  *   An associative array containing:
  *   - name: The human-readable name of the content type.
  *   - type: An object containing the 'type' (machine name) and 'description' of
  *     the content type.
- *
- * @return string
- *   An HTML-formatted string of the description for this node type.
- *
- * @ingroup themeable
  */
-function theme_node_admin_overview($variables) {
-  $name = $variables['name'];
-  $type = $variables['type'];
-
-  $output = check_plain($name);
-  $output .= ' <small>' . t('(Machine name: @type)', array('@type' => $type->type)) . '</small>';
-  $output .= '<div class="description">' . filter_xss_admin($type->description) . '</div>';
-  return $output;
+function template_preprocess_node_admin_overview(&$variables) {
+  $variables['name'] = check_plain($variables['name']);
+  $variables['description'] = filter_xss_admin($variables['type']->description);
+  $variables['machine_name'] = $variables['type']->type;
 }
 
 /**
diff --git a/core/modules/node/lib/Drupal/node/Tests/NodeFieldMultilingualTestCase.php b/core/modules/node/lib/Drupal/node/Tests/NodeFieldMultilingualTestCase.php
index f382457..7e394f3 100644
--- a/core/modules/node/lib/Drupal/node/Tests/NodeFieldMultilingualTestCase.php
+++ b/core/modules/node/lib/Drupal/node/Tests/NodeFieldMultilingualTestCase.php
@@ -134,7 +134,7 @@ function testMultilingualDisplaySettings() {
     $this->drupalGet("node/$node->nid");
     $body = $this->xpath('//article[@id=:id]//div[@class=:class]/descendant::p', array(
       ':id' => 'node-' . $node->nid,
-      ':class' => 'content',
+      ':class' => 'content ',
     ));
     $this->assertEqual(current($body), $node->body['en'][0]['value'], 'Node body found.');
   }
diff --git a/core/modules/node/node.api.php b/core/modules/node/node.api.php
index 5854170..1f71807 100644
--- a/core/modules/node/node.api.php
+++ b/core/modules/node/node.api.php
@@ -706,7 +706,7 @@ function hook_node_prepare(\Drupal\Core\Entity\EntityInterface $node) {
  *   theming.
  *
  * @see template_preprocess_search_result()
- * @see search-result.tpl.php
+ * @see search-result.html.twig
  *
  * @ingroup node_api_hooks
  */
@@ -898,8 +898,8 @@ function hook_node_view(\Drupal\Core\Entity\EntityInterface $node, \Drupal\entit
  * If the module wishes to act on the rendered HTML of the node rather than the
  * structured content array, it may use this hook to add a #post_render
  * callback.  Alternatively, it could also implement hook_preprocess_HOOK() for
- * node.tpl.php. See drupal_render() and theme() documentation respectively for
- * details.
+ * node.html.twig. See drupal_render() and theme() documentation respectively
+ * for details.
  *
  * @param $build
  *   A renderable array representing the node content.
diff --git a/core/modules/node/node.module b/core/modules/node/node.module
index 9d5fe32..573030b 100644
--- a/core/modules/node/node.module
+++ b/core/modules/node/node.module
@@ -153,24 +153,30 @@ function node_theme() {
     ),
     'node_search_admin' => array(
       'render element' => 'form',
+      'template' => 'node-search-admin',
     ),
     'node_add_list' => array(
       'variables' => array('content' => NULL),
       'file' => 'node.pages.inc',
+      'template' => 'node-add-list',
     ),
     'node_preview' => array(
       'variables' => array('node' => NULL),
       'file' => 'node.pages.inc',
+      'template' => 'node-preview',
     ),
     'node_admin_overview' => array(
       'variables' => array('name' => NULL, 'type' => NULL),
       'file' => 'content_types.inc',
+      'template' => 'node-admin-overview',
     ),
     'node_recent_block' => array(
       'variables' => array('nodes' => NULL),
+      'template' => 'node-recent-block',
     ),
     'node_recent_content' => array(
       'variables' => array('node' => NULL),
+      'template' => 'node-recent-content',
     ),
     'node_edit_form' => array(
       'render element' => 'form',
@@ -1113,7 +1119,7 @@ function node_is_page(EntityInterface $node) {
 }
 
 /**
- * Implements hook_preprocess_HOOK() for block.tpl.php.
+ * Implements hook_preprocess_HOOK() for block.html.twig.
  */
 function node_preprocess_block(&$variables) {
   if ($variables['block']->module == 'node') {
@@ -1129,19 +1135,38 @@ function node_preprocess_block(&$variables) {
 }
 
 /**
- * Processes variables for node.tpl.php.
+ * Prepares variables for node edit form templates.
  *
- * Most themes utilize their own copy of node.tpl.php. The default is located
- * inside "modules/node/node.tpl.php". Look in there for the full list of
- * variables.
+ * Default template: node-edit-form.html.twig.
  *
- * @param $variables
+ * @param array $variables
+ *   An associative array containing:
+ *   - form: The complete node form.
+ */
+function template_preprocess_node_edit_form(&$variables) {
+  $form = $variables['form'];
+
+  // @todo Update this once http://drupal.org/node/1920886 is resolved.
+  $variables['advanced'] = $form['advanced'];
+  $variables['actions'] = $form['actions'];
+  unset($form['advanced'], $form['actions']);
+  $variables['form'] = drupal_render_children($form);
+}
+
+/**
+ * Prepares variables for node templates.
+ *
+ * Default template: node.html.twig.
+ *
+ * Most themes utilize their own copy of node.html.twig. The default is located
+ * inside "core/modules/node/templates/node.html.twig". Look in there for the
+ * full list of variables.
+ *
+ * @param array $variables
  *   An associative array containing:
  *   - elements: An array of elements to display in view mode.
  *   - node: The node object.
  *   - view_mode: View mode; e.g., 'full', 'teaser'...
- *
- * @see node.tpl.php
  */
 function template_preprocess_node(&$variables) {
   $variables['view_mode'] = $variables['elements']['#view_mode'];
@@ -1150,25 +1175,18 @@ function template_preprocess_node(&$variables) {
   $variables['node'] = $variables['elements']['#node'];
   $node = $variables['node'];
 
-  $variables['date']      = format_date($node->created);
-  $variables['name']      = theme('username', array(
+  $variables['date'] = format_date($node->created);
+  // @todo Change 'name' to 'author' and also convert to a render array pending
+  //   http://drupal.org/node/1941286.
+  $variables['name'] = theme('username', array(
     'account' => $node,
     'link_attributes' => array('rel' => 'author'),
   ));
 
   $uri = $node->uri();
   $variables['node_url']  = url($uri['path'], $uri['options']);
-  $variables['label']     = check_plain($node->label());
-  $variables['page']      = $variables['view_mode'] == 'full' && node_is_page($node);
-
-  // Make useful flags and node data available.
-  // @todo: The comment properties only exist if comment.module is enabled, but
-  //   are documented in node.tpl.php, so we make sure that they are set.
-  //   Consider removing them.
-  $properties = array('type', 'comment_count', 'uid', 'created', 'promote', 'sticky', 'status', 'comment');
-  foreach ($properties as $property) {
-    $variables[$property] = isset($node->$property) ? $node->$property : NULL;
-  }
+  $variables['label'] = check_plain($node->label());
+  $variables['page'] = $variables['view_mode'] == 'full' && node_is_page($node);
 
   // Helpful $content variable for templates.
   $variables += array('content' => array());
@@ -1344,7 +1362,7 @@ function node_search_admin() {
   );
   $form['content_ranking']['#theme'] = 'node_search_admin';
   $form['content_ranking']['info'] = array(
-    '#value' => '<em>' . t('The following numbers control which properties the content search should favor when ordering the results. Higher numbers mean more influence, zero means the property is ignored. Changing these numbers does not require the search index to be rebuilt. Changes take effect immediately.') . '</em>'
+    '#markup' => '<em>' . t('The following numbers control which properties the content search should favor when ordering the results. Higher numbers mean more influence, zero means the property is ignored. Changing these numbers does not require the search index to be rebuilt. Changes take effect immediately.') . '</em>'
   );
 
   // Note: reversed to reflect that higher number = higher ranking.
@@ -1515,19 +1533,19 @@ function node_user_predelete($account) {
 }
 
 /**
- * Returns HTML for the content ranking part of the search settings admin page.
+ * Prepares variables for node search admin form templates.
  *
- * @param $variables
+ * Default template: node-search-admin.html.twig.
+ *
+ * @param array $variables
  *   An associative array containing:
  *   - form: A render element representing the form.
  *
  * @see node_search_admin()
- * @ingroup themeable
  */
-function theme_node_search_admin($variables) {
+function template_preprocess_node_search_admin(&$variables) {
   $form = $variables['form'];
-
-  $output = drupal_render($form['info']);
+  $variables['info'] = $form['info'];
 
   $header = array(t('Factor'), t('Weight'));
   foreach (element_children($form['factors']) as $key) {
@@ -1537,10 +1555,15 @@ function theme_node_search_admin($variables) {
     $row[] = drupal_render($form['factors'][$key]);
     $rows[] = $row;
   }
-  $output .= theme('table', array('header' => $header, 'rows' => $rows));
 
-  $output .= drupal_render_children($form);
-  return $output;
+  $variables['table'] = array(
+    '#theme' => 'table',
+    '#header' => $header,
+    '#rows' => $rows,
+  );
+  // @todo Remove this once http://drupal.org/node/1920886 is resolved.
+  unset($form['info']);
+  $variables['form'] = drupal_render_children($form);
 }
 
 /**
@@ -1923,23 +1946,27 @@ function node_get_recent($number = 10) {
 }
 
 /**
- * Returns HTML for a list of recent content.
+ * Prepares variables for list of recent content templates.
+ *
+ * Default template: node-recent-content.html.twig.
  *
- * @param $variables
+ * @param array $variables
  *   An associative array containing:
  *   - nodes: An array of recent node entities.
  *
- * @ingroup themeable
+ * @see template_preprocess_node_recent_content()
  */
-function theme_node_recent_block($variables) {
+function template_preprocess_node_recent_block(&$variables) {
   $rows = array();
-  $output = '';
 
   $l_options = array('query' => drupal_get_destination());
   foreach ($variables['nodes'] as $node) {
     $row = array();
     $row[] = array(
-      'data' => theme('node_recent_content', array('node' => $node)),
+      'data' => array(
+        '#theme' => 'node_recent_content',
+        '#node' => $node,
+      ),
       'class' => 'title-author',
     );
     if (node_access('update', $node)) {
@@ -1957,36 +1984,44 @@ function theme_node_recent_block($variables) {
     $rows[] = $row;
   }
 
+  $variables['table'] = array(
+    '#theme' => 'table',
+  );
+  $variables['more_link'] = array();
   if ($rows) {
-    $output = theme('table', array('rows' => $rows));
+    $variables['table']['#rows'] = $rows;
     if (user_access('access content overview')) {
-      $output .= theme('more_link', array('url' => 'admin/content', 'title' => t('Show more content')));
+      $variables['more_link'] = array(
+        '#theme' => 'more_link',
+        '#url' => 'admin/content',
+        '#title' => t('Show more content'),
+      );
     }
   }
-
-  return $output;
 }
 
 /**
- * Returns HTML for a recent node to be displayed in the recent content block.
+ * Prepares variables for recently created node templates.
+ *
+ * Default template: node-recent-content.twig.
  *
- * @param $variables
+ * @param array $variables
  *   An associative array containing:
  *   - node: A node entity.
  *
- * @ingroup themeable
+ * @see template_preprocess_node_recent_block()
  */
-function theme_node_recent_content($variables) {
+function template_preprocess_node_recent_content(&$variables) {
   $node = $variables['node'];
-
-  $output = '<div class="node-title">';
-  $output .= l($node->label(), 'node/' . $node->nid);
-  $output .= theme('mark', array('type' => node_mark($node->nid, $node->changed)));
-  $output .= '</div><div class="node-author">';
-  $output .= theme('username', array('account' => user_load($node->uid)));
-  $output .= '</div>';
-
-  return $output;
+  $variables['link'] = l($node->label(), 'node/' . $node->nid);
+  $variables['mark'] = array(
+    '#theme' => 'mark',
+    '#type' => node_mark($node->nid, $node->changed),
+  );
+  $variables['username'] = array(
+    '#theme' => 'username',
+    '#account' => user_load($node->uid),
+  );
 }
 
 /**
diff --git a/core/modules/node/node.pages.inc b/core/modules/node/node.pages.inc
index 863babd..28d78b4 100644
--- a/core/modules/node/node.pages.inc
+++ b/core/modules/node/node.pages.inc
@@ -56,32 +56,27 @@ function node_add_page() {
 }
 
 /**
- * Returns HTML for a list of available node types for node creation.
+ * Prepares variables for available node types list templates.
  *
- * @param $variables
+ * Default template: node-add-list.html.twig.
+ *
+ * @param array $variables
  *   An associative array containing:
  *   - content: An array of content types.
  *
  * @see node_add_page()
- *
- * @ingroup themeable
  */
-function theme_node_add_list($variables) {
-  $content = $variables['content'];
-  $output = '';
-
-  if ($content) {
-    $output = '<dl class="node-type-list">';
-    foreach ($content as $type) {
-      $output .= '<dt>' . l($type->name, 'node/add/' . $type->type) . '</dt>';
-      $output .= '<dd>' . filter_xss_admin($type->description) . '</dd>';
+function template_preprocess_node_add_list(&$variables) {
+  $variables['types'] = array();
+  if (!empty($variables['content'])) {
+    foreach ($variables['content'] as $type) {
+      $variables['types'][$type->type] = array(
+        'type' => $type->type,
+        'add_link' => l($type->name, 'node/add/' . $type->type),
+        'description' => filter_xss_admin($type->description),
+      );
     }
-    $output .= '</dl>';
   }
-  else {
-    $output = '<p>' . t('You have not created any content types yet. Go to the <a href="@create-content">content type creation page</a> to add a new content type.', array('@create-content' => url('admin/structure/types/add'))) . '</p>';
-  }
-  return $output;
 }
 
 
@@ -157,41 +152,37 @@ function node_preview(EntityInterface $node) {
 }
 
 /**
- * Returns HTML for a node preview for display during node creation and editing.
+ * Prepares variables for node preview templates.
  *
- * @param $variables
+ * Default template: node-preview.html.twig.
+ *
+ * @param array $variables
  *   An associative array containing:
  *   - node: The node entity which is being previewed.
  *
  * @see NodeFormController::preview()
  * @see node_preview()
- *
- * @ingroup themeable
  */
-function theme_node_preview($variables) {
+function template_preprocess_node_preview(&$variables) {
   $node = $variables['node'];
 
-  $output = '';
-
-  $elements = node_view($node, 'teaser');
-  $elements['#attached']['library'][] = array('node', 'drupal.node.preview');
-  $trimmed = drupal_render($elements);
-  $elements = node_view($node, 'full');
-  $full = drupal_render($elements);
-
-  // Do we need to preview trimmed version of post as well as full version?
-  if ($trimmed != $full) {
+  // Render trimmed teaser version of the post.
+  $node_teaser = node_view($node, 'teaser');
+  $node_teaser['#attached']['library'][] = array('node', 'drupal.node.preview');
+  $variables['teaser'] = $node_teaser;
+  // Render full version of the post.
+  $node_full = node_view($node, 'full');
+  $variables['full'] = $node_full;
+
+  // Do we need to preview a trimmed teaser version of a post as well as a full
+  // version?
+  if ($variables['teaser'] != $variables['full']) {
     drupal_set_message(t('The trimmed version of your post shows what your post looks like when promoted to the main page or when exported for syndication.<span class="no-js"> You can insert the delimiter "&lt;!--break--&gt;" (without the quotes) to fine-tune where your post gets split.</span>'));
-    $output .= '<h3>' . t('Preview trimmed version') . '</h3>';
-    $output .= $trimmed;
-    $output .= '<h3>' . t('Preview full version') . '</h3>';
-    $output .= $full;
+    $variables['preview_teaser'] = TRUE;
   }
   else {
-    $output .= $full;
+    $variables['preview_teaser'] = FALSE;
   }
-
-  return $output;
 }
 
 /**
diff --git a/core/modules/node/templates/node-add-list.html.twig b/core/modules/node/templates/node-add-list.html.twig
new file mode 100644
index 0000000..d1d7670
--- /dev/null
+++ b/core/modules/node/templates/node-add-list.html.twig
@@ -0,0 +1,26 @@
+{#
+/**
+ * @file
+ * Default theme implementation to list the available types for content creation.
+ *
+ * Available variables:
+ * - types: A list of content types.
+ *   - type.add_link: Link to create a piece of content of this type.
+ *   - type.description: Description of this type of content.
+ *
+ * @see template_preprocess()
+ * @see template_preprocess_node_add_list()
+ *
+ * @ingroup themeable
+ */
+#}
+{% if types is not empty %}
+  <dl class="node-type-list">
+    {% for type in types %}
+      <dt>{{ type.add_link }}</dt>
+      <dd>{{ type.description }}</dd>
+    {% endfor %}
+  </dl>
+{% else %}
+  <p>{{ 'You have not created any content types yet. Go to the <a href="@create-content">content type creation page</a> to add a new content type.'|t({'@create-content': url('admin/structure/types/add')}) }}</p>
+{% endif %}
diff --git a/core/modules/node/templates/node-admin-overview.html.twig b/core/modules/node/templates/node-admin-overview.html.twig
new file mode 100644
index 0000000..7ea022b
--- /dev/null
+++ b/core/modules/node/templates/node-admin-overview.html.twig
@@ -0,0 +1,19 @@
+{#
+/**
+ * @file
+ * Default theme implementation for a node type description for the
+ * content type admin page.
+ *
+ * Available variables:
+ * - name: Human readable name of the content type.
+ * - machine_name: Machine readable name of the content type.
+ * - description: Description of the content type.
+ *
+ * @see template_preprocess()
+ * @see template_preprocess_node_admin_overview()
+ *
+ * @ingroup themeable
+ */
+#}
+{{ name }} <small>{{ '(Machine name: @type)'|t({'@type': machine_name}) }}</small>
+<div class="description">{{ description }}</div>
diff --git a/core/modules/node/templates/node-edit-form.html.twig b/core/modules/node/templates/node-edit-form.html.twig
new file mode 100644
index 0000000..9840a5e
--- /dev/null
+++ b/core/modules/node/templates/node-edit-form.html.twig
@@ -0,0 +1,25 @@
+{#
+/**
+ * @file
+ * Two column template for the node add/edit form.
+ *
+ * Available variables:
+ * - form: The remainder of the node edit form, after advanced and actions
+ *   have been hidden.
+ * - advanced: The advanced options for the node form.
+ * - actions: The action buttons for save and delete.
+ *
+ * @ingroup themable
+ */
+#}
+<div class="layout-node-form clearfix">
+  <div class="layout-region layout-region-node-main">
+    {{ form }}
+  </div>
+  <div class="layout-region layout-region-node-secondary">
+    {{ advanced }}
+  </div>
+  <div class="layout-region layout-region-node-footer">
+    {{ actions }}
+  </div>
+</div>
diff --git a/core/modules/node/templates/node-edit-form.tpl.php b/core/modules/node/templates/node-edit-form.tpl.php
deleted file mode 100644
index 7b76683..0000000
--- a/core/modules/node/templates/node-edit-form.tpl.php
+++ /dev/null
@@ -1,27 +0,0 @@
-<?php
-
-/**
- * @file
- * Two column template for the node add/edit form.
- *
- * Available variables:
- * - $form: The actual form to print.
- */
-
-hide($form['advanced']);
-hide($form['actions']);
-
-?>
-<div class="layout-node-form clearfix">
-  <div class="layout-region layout-region-node-main">
-    <?php print drupal_render_children($form); ?>
-  </div>
-
-  <div class="layout-region layout-region-node-secondary">
-    <?php print render($form['advanced']); ?>
-  </div>
-
-  <div class="layout-region layout-region-node-footer">
-    <?php print render($form['actions']); ?>
-  </div>
-</div>
diff --git a/core/modules/node/templates/node-preview.html.twig b/core/modules/node/templates/node-preview.html.twig
new file mode 100644
index 0000000..aa8ec0e
--- /dev/null
+++ b/core/modules/node/templates/node-preview.html.twig
@@ -0,0 +1,24 @@
+{#
+/**
+ * @file
+ * Default theme implementation for a node preview.
+ *
+ * This display may be used during node creation and editing.
+ *
+ * Available variables:
+ * - preview_teaser: Flag indicating whether to show a trimmed teaser version.
+ * - teaser: Trimmed teaser version of the node.
+ * - full: Full version of the node.
+ *
+ * @see template_preprocess()
+ * @see template_preprocess_node_preview()
+ *
+ * @ingroup themeable
+ */
+#}
+{% if preview_teaser %}
+  <h3>{{ "Preview trimmed version"|t }}</h3>
+  {{ teaser }}
+  <h3>{{ "Preview full version"|t }}</h3>
+{% endif %}
+{{ full }}
diff --git a/core/modules/node/templates/node-recent-block.html.twig b/core/modules/node/templates/node-recent-block.html.twig
new file mode 100644
index 0000000..b8cfd81
--- /dev/null
+++ b/core/modules/node/templates/node-recent-block.html.twig
@@ -0,0 +1,21 @@
+{#
+/**
+ * @file
+ * Default theme implementation for a list of recent content.
+ *
+ * Available variables:
+ * - table: A rendered HTML table of recent content.
+ * - more_link: A rendered link to show more content.
+ *
+ * @see template_preprocess()
+ * @see template_preprocess_node_recent_block()
+ *
+ * @ingroup themeable
+ */
+#}
+{% if table %}
+  {{ table }}
+{% endif %}
+{% if more_link %}
+  {{ more_link }}
+{% endif %}
diff --git a/core/modules/node/templates/node-recent-content.html.twig b/core/modules/node/templates/node-recent-content.html.twig
new file mode 100644
index 0000000..ef52547
--- /dev/null
+++ b/core/modules/node/templates/node-recent-content.html.twig
@@ -0,0 +1,18 @@
+{#
+/**
+ * @file
+ * Default theme implementation for a recent node to be displayed in the recent content block.
+ *
+ * Available variables:
+ * - link: Link to the content.
+ * - mark: HTML marker for new or updated content.
+ * - username: The author of the content.
+ *
+ * @see template_preprocess()
+ * @see template_preprocess_node_recent_content()
+ *
+ * @ingroup themeable
+ */
+#}
+<div class="node-title">{{ link }}{{ mark }}</div>
+<div class="node-author">{{ username }}</div>
diff --git a/core/modules/node/templates/node-search-admin.html.twig b/core/modules/node/templates/node-search-admin.html.twig
new file mode 100644
index 0000000..1a409e9
--- /dev/null
+++ b/core/modules/node/templates/node-search-admin.html.twig
@@ -0,0 +1,20 @@
+{#
+/**
+ * @file
+ * Default theme implementation for the content ranking part of the search
+ * settings admin page.
+ *
+ * Available variables:
+ * - info: Information for the user about the search ranking settings form.
+ * - table: The table of the settings.
+ * - form: A render element representing the form.
+ *
+ * @see template_preprocess()
+ * @see template_preprocess_node_search_admin()
+ *
+ * @ingroup themeable
+ */
+#}
+{{ info }}
+{{ table }}
+{{ form }}
diff --git a/core/modules/node/templates/node.html.twig b/core/modules/node/templates/node.html.twig
index f1e0b5a..dbf1d1a 100644
--- a/core/modules/node/templates/node.html.twig
+++ b/core/modules/node/templates/node.html.twig
@@ -4,57 +4,50 @@
  * Default theme implementation to display a node.
  *
  * Available variables:
- * - label: the title of the node.
- * - content: node items. Use {{ content }} to print them all,
+ * - label: The node title.
+ * - content: All node items. Use {{ content }} to print them all,
  *   or print a subset such as {{ content.field_example }}. Use
  *   {% hide(content.field_example) %} to temporarily suppress the printing
  *   of a given element.
+ * - name: Themed username of node author output from username.html.twig.
  * - user_picture: The node author's picture from user-picture.html.twig.
- * - date: Formatted creation date. Preprocess functions can reformat it by
- *   calling format_date() with the desired parameters on
- *   $variables['created'].
- * - name: Themed username of node author output from theme_username().
  * - node_url: Direct URL of the current node.
  * - display_submitted: Whether submission information should be displayed.
- * - submitted: Submission information created from name and date during
- *   template_preprocess_node().
- * - attributes: HTML attributes for the surrounding element.
- *    Attributes include the 'class' information, which contains:
- *   - node: The current template type; for example, "theming hook".
+ * - attributes: Remaining HTML attributes for the containing element.
+ * - attributes.class: Class information, containing:
+ *   - node: The current template type (also known as a "theming hook").
  *   - node-[type]: The current node type. For example, if the node is a
  *     "Article" it would result in "node-article". Note that the machine
  *     name will often be in a short form of the human readable label.
- *   - view-mode-[view_mode]: The View Mode of the node; for example, "teaser"
- *     or "full".
- *   - preview: Nodes in preview mode.
+ *   - view-mode-[view_mode]: The View Mode of the node; for example, a teaser
+ *     would result in: "view-mode-teaser", and full: "view-mode-full".
+ *   - preview: Whether a node is in preview mode.
  *   The following are controlled through the node publishing options.
- *   - promoted: Nodes promoted to the front page.
- *   - sticky: Nodes ordered above other non-sticky nodes in teaser
+ *   - promoted: Appears on nodes promoted to the front page.
+ *   - sticky: Appears on nodes ordered above other non-sticky nodes in teaser
  *     listings.
- *   - unpublished: Unpublished nodes visible only to administrators.
+ *   - unpublished: Appears on unpublished nodes visible only to site admins.
  * - title_prefix: Additional output populated by modules, intended to be
  *   displayed in front of the main title tag that appears in the template.
  * - title_suffix: Additional output populated by modules, intended to be
  *   displayed after the main title tag that appears in the template.
  *
  * Other variables:
- * - node: Fully loaded node entity.
- * - type: Node type; for example, page, article, etc.
- * - comment_count: Number of comments attached to the node.
- * - uid: User ID of the node author.
- * - created: Time the node was published formatted as a Unix timestamp.
+ * - node: Full node entity.
+ *   - node.type: Node type; for example, "page" or "article".
+ *   - node.uid: User ID of the node author.
+ *   - node.created: Formatted creation date.
+ *   - node.promote: Flag for front page promotion state.
+ *   - node.sticky: Flag for sticky post setting.
+ *   - node.status: Flag for published status.
+ *   - node.comment: State of comment settings for the node.
+ *   - node.comment_count: Number of comments attached to the node.
  * - zebra: Outputs either "even" or "odd". Useful for zebra striping in
  *   teaser listings.
  * - id: Position of the node. Increments each time it's output.
- *
- * Node status variables:
  * - view_mode: View mode; for example, "teaser" or "full".
  * - teaser: Flag for the teaser state. Will be true if view_mode is 'teaser'.
  * - page: Flag for the full page state. Will be true if view_mode is 'full'.
- * - promote: Flag for front page promotion state.
- * - sticky: Flag for sticky post setting.
- * - status: Flag for published status.
- * - comment: State of comment settings for the node.
  * - readmore: Flag for more state. Will be true if the teaser content of the
  *   node cannot hold the main body content.
  * - is_front: Flag for front. Will be true when presented on the front page.
@@ -64,25 +57,27 @@
  *   is an administrator.
  *
  * Field variables: for each field instance attached to the node a corresponding
- * variable is defined; for example, $node->body becomes body. When needing to
+ * variable is defined; for example, 'node.body' becomes 'body'. When needing to
  * access a field's raw values, developers/themers are strongly encouraged to
  * use these variables. Otherwise they will have to explicitly specify the
- * desired field language; for example, $node->body['en'], thus overriding any
- * language negotiation rule that was previously applied.
+ * desired field language; for example, 'node.body.en', thus overriding any
+ * language negotiation rule that may have been applied previously.
  *
  * @see template_preprocess()
  * @see template_preprocess_node()
  *
+ * @todo Remove the id attribute (or make it a class), because if that gets
+ *   rendered twice on a page this is invalid CSS for example: two lists
+ *   in different view modes.
+ *
  * @ingroup themeable
  */
 #}
-<article id="node-{{ node.nid }}" class="{{ attributes.class }} clearfix"{{ attributes }}>
+<article id="node-{{ node.nid }}" class="clearfix {{ attributes.class }}"{{ attributes }}>
 
   {{ title_prefix }}
   {% if not page %}
-    <h2{{ title_attributes }}>
-      <a href="{{ node_url }}" rel="bookmark">{{ label }}</a>
-    </h2>
+    <h2{{ title_attributes }}><a href="{{ node_url }}" rel="bookmark">{{ label }}</a></h2>
   {% endif %}
   {{ title_suffix }}
 
@@ -93,7 +88,7 @@
     </footer>
   {% endif %}
 
-  <div class="content"{{ content_attributes }}>
+  <div class="content {{ content_attributes.class }}"{{ content_attributes }}>
     {# We hide the comments and links now so that we can render them later. #}
     {% hide(content.comments) %}
     {% hide(content.links) %}
diff --git a/core/modules/node/templates/node.tpl.php b/core/modules/node/templates/node.tpl.php
deleted file mode 100644
index 196d26f..0000000
--- a/core/modules/node/templates/node.tpl.php
+++ /dev/null
@@ -1,106 +0,0 @@
-<?php
-
-/**
- * @file
- * Default theme implementation to display a node.
- *
- * Available variables:
- * - $label: the (sanitized) title of the node.
- * - $content: An array of node items. Use render($content) to print them all,
- *   or print a subset such as render($content['field_example']). Use
- *   hide($content['field_example']) to temporarily suppress the printing of a
- *   given element.
- * - $user_picture: The node author's picture. Use render() to print it.
- * - $date: Formatted creation date. Preprocess functions can reformat it by
- *   calling format_date() with the desired parameters on the $created variable.
- * - $name: Themed username of node author output from theme_username().
- * - $node_url: Direct URL of the current node.
- * - $display_submitted: Whether submission information should be displayed.
- * - $submitted: Submission information created from $name and $date during
- *   template_preprocess_node().
- * - $attributes: An instance of Attributes class that can be manipulated as an
- *    array and printed as a string.
- *    It includes the 'class' information, which includes:
- *   - node: The current template type; for example, "theming hook".
- *   - node-[type]: The current node type. For example, if the node is a
- *     "Article" it would result in "node-article". Note that the machine
- *     name will often be in a short form of the human readable label.
- *   - view-mode-[view_mode]: The View Mode of the node; for example, "teaser"
- *     or "full".
- *   - preview: Nodes in preview mode.
- *   The following are controlled through the node publishing options.
- *   - promoted: Nodes promoted to the front page.
- *   - sticky: Nodes ordered above other non-sticky nodes in teaser
- *     listings.
- *   - unpublished: Unpublished nodes visible only to administrators.
- * - $title_prefix (array): An array containing additional output populated by
- *   modules, intended to be displayed in front of the main title tag that
- *   appears in the template.
- * - $title_suffix (array): An array containing additional output populated by
- *   modules, intended to be displayed after the main title tag that appears in
- *   the template.
- *
- * Other variables:
- * - $node: Full node entity. Contains data that may not be safe.
- * - $type: Node type; for example, page, article, etc.
- * - $comment_count: Number of comments attached to the node.
- * - $uid: User ID of the node author.
- * - $created: Time the node was published formatted in Unix timestamp.
- * - $zebra: Outputs either "even" or "odd". Useful for zebra striping in
- *   teaser listings.
- * - $id: Position of the node. Increments each time it's output.
- *
- * Node status variables:
- * - $view_mode: View mode; for example, "teaser" or "full".
- * - $teaser: Flag for the teaser state (shortcut for $view_mode == 'teaser').
- * - $page: Flag for the full page state.
- * - $promote: Flag for front page promotion state.
- * - $sticky: Flags for sticky post setting.
- * - $status: Flag for published status.
- * - $comment: State of comment settings for the node.
- * - $is_front: Flags true when presented in the front page.
- * - $logged_in: Flags true when the current user is a logged-in member.
- * - $is_admin: Flags true when the current user is an administrator.
- *
- * Field variables: for each field instance attached to the node a corresponding
- * variable is defined; for example, $node->body becomes $body. When needing to
- * access a field's raw values, developers/themers are strongly encouraged to
- * use these variables. Otherwise they will have to explicitly specify the
- * desired field language; for example, $node->body['en'], thus overriding any
- * language negotiation rule that was previously applied.
- *
- * @see template_preprocess()
- * @see template_preprocess_node()
- * @see template_process()
- *
- * @ingroup themeable
- */
-?>
-<article id="node-<?php print $node->nid; ?>" class="<?php print $attributes['class']; ?> clearfix"<?php print $attributes; ?>>
-
-  <?php print render($title_prefix); ?>
-  <?php if (!$page): ?>
-    <h2<?php print $title_attributes; ?>><a href="<?php print $node_url; ?>" rel="bookmark"><?php print $label; ?></a></h2>
-  <?php endif; ?>
-  <?php print render($title_suffix); ?>
-
-  <?php if ($display_submitted): ?>
-    <footer>
-      <?php print render($user_picture); ?>
-      <p class="submitted"><?php print $submitted; ?></p>
-    </footer>
-  <?php endif; ?>
-
-  <div class="content"<?php print $content_attributes; ?>>
-    <?php
-      // We hide the comments and links now so that we can render them later.
-      hide($content['comments']);
-      hide($content['links']);
-      print render($content);
-    ?>
-  </div>
-
-  <?php print render($content['links']); ?>
-  <?php print render($content['comments']); ?>
-
-</article>
