diff --git a/core/includes/theme.inc b/core/includes/theme.inc
index 0a04480..6a4fd71 100644
--- a/core/includes/theme.inc
+++ b/core/includes/theme.inc
@@ -1986,6 +1986,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 e67657c..22b92b4 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;
 
 /**
@@ -138,6 +139,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
@@ -265,6 +267,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 6cd0960..36febf5 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);
 
+  /**
+   * Preprocess 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 200b428..d7533c2 100644
--- a/core/modules/block/lib/Drupal/block/BlockViewBuilder.php
+++ b/core/modules/block/lib/Drupal/block/BlockViewBuilder.php
@@ -99,4 +99,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 6d7e051..a3777f8 100644
--- a/core/modules/comment/comment.module
+++ b/core/modules/comment/comment.module
@@ -1381,9 +1381,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 = entity_load($comment->entity_type->value, $comment->entity_id->value);
-  $variables['comment'] = $comment;
   $variables['commented_entity'] = $commented_entity;
 
   $account = comment_prepare_author($comment);
@@ -1469,11 +1468,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';
@@ -1483,7 +1477,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 4b80b36..c71085d 100644
--- a/core/modules/node/node.module
+++ b/core/modules/node/node.module
@@ -641,10 +641,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'];
 
@@ -661,12 +659,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());
@@ -693,7 +685,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/taxonomy/taxonomy.module b/core/modules/taxonomy/taxonomy.module
index f2fe6fe..037225f 100644
--- a/core/modules/taxonomy/taxonomy.module
+++ b/core/modules/taxonomy/taxonomy.module
@@ -396,26 +396,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 f9b5a91..2f5ca22 100644
--- a/core/modules/user/user.pages.inc
+++ b/core/modules/user/user.pages.inc
@@ -106,13 +106,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';
 }
