diff --git a/core/includes/theme.inc b/core/includes/theme.inc
index 2e7d41e..fed7da7 100644
--- a/core/includes/theme.inc
+++ b/core/includes/theme.inc
@@ -2001,6 +2001,12 @@ function template_preprocess(&$variables, $hook, $info) {
       $variables['attributes'] = NestedArray::mergeDeep($variables['attributes'], $variables[$key]['#attributes']);
     }
   }
+
+  // If this is an entity being rendered, call the preprocess() method on the
+  // view builder.
+  if (isset($variables['elements']['#entity_type']) && isset($variables['elements']['#view_mode'])) {
+    \Drupal::entityManager()->getViewBuilder($variables['elements']['#entity_type'])->preprocess($variables);
+  }
 }
 
 /**
diff --git a/core/lib/Drupal/Core/Entity/EntityViewBuilder.php b/core/lib/Drupal/Core/Entity/EntityViewBuilder.php
index 3ac6441..af0e992 100644
--- a/core/lib/Drupal/Core/Entity/EntityViewBuilder.php
+++ b/core/lib/Drupal/Core/Entity/EntityViewBuilder.php
@@ -12,6 +12,7 @@
 use Drupal\Core\Language\Language;
 use Drupal\Core\Language\LanguageManagerInterface;
 use Drupal\entity\Entity\EntityViewDisplay;
+use Drupal\Core\Render\Element;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -143,6 +144,7 @@ protected function getBuildDefaults(EntityInterface $entity, $view_mode, $langco
       "#{$this->entityTypeId}" => $entity,
       '#view_mode' => $view_mode,
       '#langcode' => $langcode,
+      '#entity_type' => $this->entityTypeId,
     );
 
     // Cache the rendered output if permitted by the view mode and global entity
@@ -273,6 +275,29 @@ public function resetCache(array $entities = NULL) {
   }
 
   /**
+   * {@inheritdoc}
+   */
+  public function preprocess(array &$variables) {
+    // Only do anything if the entity follows the standard naming convention.
+    if (!isset($variables['elements']['#' . $this->entityTypeId])) {
+      return;
+    }
+
+    $variables['view_mode'] = $variables['elements']['#view_mode'];
+    $entity = $variables['elements']['#' . $this->entityTypeId];
+    $variables[$this->entityTypeId] = $entity;
+    $variables['url'] = $entity->url();
+
+    // Helpful $content variable for templates.
+    $variables += array('content' => array());
+    foreach (Element::children($variables['elements']) as $key) {
+      $variables['content'][$key] = $variables['elements'][$key];
+    }
+
+    $variables['attributes']['class'][] = $this->entityTypeId;
+  }
+
+  /**
    * Returns TRUE if the view mode is cacheable.
    *
    * @param string $view_mode
diff --git a/core/lib/Drupal/Core/Entity/EntityViewBuilderInterface.php b/core/lib/Drupal/Core/Entity/EntityViewBuilderInterface.php
index 14e4ba0..878e4a4 100644
--- a/core/lib/Drupal/Core/Entity/EntityViewBuilderInterface.php
+++ b/core/lib/Drupal/Core/Entity/EntityViewBuilderInterface.php
@@ -84,4 +84,12 @@ public function viewMultiple(array $entities = array(), $view_mode = 'full', $la
    */
   public function resetCache(array $entities = NULL);
 
+  /**
+   * Preprocesses variables.
+   *
+   * @param array $variables
+   *   An associative array containing the entity variables to be rendered.
+   */
+  public function preprocess(array &$variables);
+
 }
diff --git a/core/modules/block/lib/Drupal/block/BlockViewBuilder.php b/core/modules/block/lib/Drupal/block/BlockViewBuilder.php
index a076dc9..298631a 100644
--- a/core/modules/block/lib/Drupal/block/BlockViewBuilder.php
+++ b/core/modules/block/lib/Drupal/block/BlockViewBuilder.php
@@ -100,4 +100,10 @@ public function viewMultiple(array $entities = array(), $view_mode = 'full', $la
    */
   public function resetCache(array $ids = NULL) { }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function preprocess(array &$variables) {
+  }
+
 }
diff --git a/core/modules/comment/comment.module b/core/modules/comment/comment.module
index 0cbe24c..1ecf4ce 100644
--- a/core/modules/comment/comment.module
+++ b/core/modules/comment/comment.module
@@ -1396,9 +1396,8 @@ function comment_prepare_author(CommentInterface $comment) {
  */
 function template_preprocess_comment(&$variables) {
   /** @var \Drupal\comment\CommentInterface $comment */
-  $comment = $variables['elements']['#comment'];
+  $comment = $variables['comment'];
   $commented_entity = $comment->getCommentedEntity();
-  $variables['comment'] = $comment;
   $variables['commented_entity'] = $commented_entity;
 
   $account = comment_prepare_author($comment);
@@ -1482,11 +1481,6 @@ function template_preprocess_comment(&$variables) {
     $variables['parent'] = '';
   }
 
-  // Helpful $content variable for templates.
-  foreach (element_children($variables['elements']) as $key) {
-    $variables['content'][$key] = $variables['elements'][$key];
-  }
-
   // Set status to a string representation of comment->status.
   if (isset($comment->in_preview)) {
     $variables['status'] = 'preview';
@@ -1496,7 +1490,6 @@ function template_preprocess_comment(&$variables) {
   }
 
   // Gather comment classes.
-  $variables['attributes']['class'][] = 'comment';
   // 'published' class is not needed, it is either 'preview' or 'unpublished'.
   if ($variables['status'] != 'published') {
     $variables['attributes']['class'][] = $variables['status'];
diff --git a/core/modules/node/node.module b/core/modules/node/node.module
index 5bef612..c4a7f14 100644
--- a/core/modules/node/node.module
+++ b/core/modules/node/node.module
@@ -643,10 +643,8 @@ function node_theme_suggestions_node(array $variables) {
  *   - view_mode: View mode; e.g., 'full', 'teaser'...
  */
 function template_preprocess_node(&$variables) {
-  $variables['view_mode'] = $variables['elements']['#view_mode'];
   // Provide a distinct $teaser boolean.
   $variables['teaser'] = $variables['view_mode'] == 'teaser';
-  $variables['node'] = $variables['elements']['#node'];
   /** @var \Drupal\node\NodeInterface $node */
   $node = $variables['node'];
 
@@ -663,12 +661,6 @@ function template_preprocess_node(&$variables) {
   unset($variables['elements']['title']);
   $variables['page'] = $variables['view_mode'] == 'full' && node_is_page($node);
 
-  // Helpful $content variable for templates.
-  $variables += array('content' => array());
-  foreach (element_children($variables['elements']) as $key) {
-    $variables['content'][$key] = $variables['elements'][$key];
-  }
-
   // Display post information only on certain node types.
   // Avoid loading the entire node type config entity here that may not exist.
   $node_type_config = \Drupal::config('node.type.' . $node->bundle());
@@ -695,7 +687,6 @@ function template_preprocess_node(&$variables) {
   $variables['attributes']['role'] = 'article';
 
   // Gather node classes.
-  $variables['attributes']['class'][] = 'node';
   $variables['attributes']['class'][] = drupal_html_class('node-' . $node->bundle());
   if ($node->isPromoted()) {
     $variables['attributes']['class'][] = 'promoted';
diff --git a/core/modules/rdf/rdf.module b/core/modules/rdf/rdf.module
index 01cb430..a585995 100644
--- a/core/modules/rdf/rdf.module
+++ b/core/modules/rdf/rdf.module
@@ -516,7 +516,8 @@ function rdf_preprocess_comment(&$variables) {
  * Implements hook_preprocess_HOOK() for taxonomy term templates.
  */
 function rdf_preprocess_taxonomy_term(&$variables) {
-  $term = $variables['term'];
+  /* @var \Drupal\taxonomy\TermInterface $term */
+  $term = $variables['taxonomy_term'];
   $mapping = rdf_get_mapping('taxonomy_term', $term->bundle());
   $bundle_mapping = $mapping->getPreparedBundleMapping();
   $name_field_mapping = $mapping->getPreparedFieldMapping('name');
diff --git a/core/modules/taxonomy/taxonomy.module b/core/modules/taxonomy/taxonomy.module
index 3124f63..4221d16 100644
--- a/core/modules/taxonomy/taxonomy.module
+++ b/core/modules/taxonomy/taxonomy.module
@@ -397,26 +397,15 @@ function taxonomy_theme_suggestions_taxonomy_term(array $variables) {
  *   - attributes: HTML attributes for the containing element.
  */
 function template_preprocess_taxonomy_term(&$variables) {
-  $variables['view_mode'] = $variables['elements']['#view_mode'];
-  $variables['term'] = $variables['elements']['#taxonomy_term'];
   /** @var \Drupal\taxonomy\TermInterface $term */
-  $term = $variables['term'];
+  $term = $variables['taxonomy_term'];
 
-  $variables['url'] = $term->url();
   // We use name here because that is what appears in the UI.
   $variables['name'] = check_plain($term->label());
   $variables['page'] = $variables['view_mode'] == 'full' && taxonomy_term_is_page($term);
 
-  // Helpful $content variable for templates.
-  $variables['content'] = array();
-  foreach (element_children($variables['elements']) as $key) {
-    $variables['content'][$key] = $variables['elements'][$key];
-  }
-
-  // Gather classes, and clean up name so there are no underscores.
-  $variables['attributes']['class'][] = 'taxonomy-term';
-  $vocabulary_name_css = str_replace('_', '-', $term->bundle());
-  $variables['attributes']['class'][] = 'vocabulary-' . $vocabulary_name_css;
+  // Add a class for the vocabulary.
+  $variables['attributes']['class'][] = drupal_html_class('vocabulary-' . $term->bundle());
 }
 
 /**
diff --git a/core/modules/taxonomy/templates/taxonomy-term.html.twig b/core/modules/taxonomy/templates/taxonomy-term.html.twig
index a3986fa..5d39ba7 100644
--- a/core/modules/taxonomy/templates/taxonomy-term.html.twig
+++ b/core/modules/taxonomy/templates/taxonomy-term.html.twig
@@ -20,7 +20,7 @@
  *     For example, if the term belongs to a vocabulary called "Tags" then the
  *     class would be "vocabulary-tags".
  * - page: Flag for the full page state.
- * - term: The taxonomy term entity, including:
+ * - taxonomy_term: The taxonomy term entity, including:
  *   - id: The ID of the taxonomy term.
  * - view_mode: View mode, e.g. 'full', 'teaser', etc.
  *
@@ -29,7 +29,7 @@
  * @ingroup themeable
  */
 #}
-<div id="taxonomy-term-{{ term.id }}"{{ attributes }}>
+<div id="taxonomy-term-{{ taxonomy_term.id }}"{{ attributes }}>
   {{ title_prefix }}
   {% if not page %}
     <h2><a href="{{ url }}">{{ name }}</a></h2>
diff --git a/core/modules/user/user.pages.inc b/core/modules/user/user.pages.inc
index e093781..6b775b6 100644
--- a/core/modules/user/user.pages.inc
+++ b/core/modules/user/user.pages.inc
@@ -107,13 +107,6 @@ function user_pass_reset($form, &$form_state, $uid, $timestamp, $hashed_pass, $a
  *   - account: The user account.
  */
 function template_preprocess_user(&$variables) {
-  $account = $variables['elements']['#user'];
-
-  // Helpful $content variable for templates.
-  foreach (element_children($variables['elements']) as $key) {
-    $variables['content'][$key] = $variables['elements'][$key];
-  }
-
   // Set up attributes.
   $variables['attributes']['class'][] = 'profile';
 }
