diff --git a/core/includes/theme.inc b/core/includes/theme.inc
index 2b06429..46a99f0 100644
--- a/core/includes/theme.inc
+++ b/core/includes/theme.inc
@@ -1882,6 +1882,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 cd1cbfb..ca42e76 100644
--- a/core/lib/Drupal/Core/Entity/EntityViewBuilder.php
+++ b/core/lib/Drupal/Core/Entity/EntityViewBuilder.php
@@ -18,6 +18,7 @@
 use Drupal\Core\TypedData\TranslatableInterface;
 use Drupal\Core\Render\Element;
 use Drupal\entity\Entity\EntityViewDisplay;
+use Drupal\Core\Render\Element;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -161,6 +162,7 @@ protected function getBuildDefaults(EntityInterface $entity, $view_mode, $langco
       '#cache' => array(
         'tags' => NestedArray::mergeDeep($this->getCacheTag(), $entity->getCacheTag()),
       ),
+      '#entity_type' => $this->entityTypeId,
     );
 
     // Cache the rendered output if permitted by the view mode and global entity
@@ -360,6 +362,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 ee1c193..2783f65 100644
--- a/core/lib/Drupal/Core/Entity/EntityViewBuilderInterface.php
+++ b/core/lib/Drupal/Core/Entity/EntityViewBuilderInterface.php
@@ -159,4 +159,12 @@ public function viewFieldItem(FieldItemInterface $item, $display_options = array
    */
   public function getCacheTag();
 
+  /**
+   * 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/src/BlockViewBuilder.php b/core/modules/block/src/BlockViewBuilder.php
index 9e3b1b5..f5f3d01 100644
--- a/core/modules/block/src/BlockViewBuilder.php
+++ b/core/modules/block/src/BlockViewBuilder.php
@@ -154,4 +154,11 @@ public function buildBlock($build) {
     return $build;
    }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function preprocess(array &$variables) {
+
+  }
+
 }
diff --git a/core/modules/comment/comment.module b/core/modules/comment/comment.module
index b09bfa8..78cfd80 100644
--- a/core/modules/comment/comment.module
+++ b/core/modules/comment/comment.module
@@ -1339,9 +1339,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);
@@ -1428,11 +1427,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';
@@ -1442,7 +1436,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 38e047b..308acd2 100644
--- a/core/modules/node/node.module
+++ b/core/modules/node/node.module
@@ -629,10 +629,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'];
 
@@ -651,12 +649,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());
@@ -683,7 +675,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 8ea735b..1c0bcfb 100644
--- a/core/modules/rdf/rdf.module
+++ b/core/modules/rdf/rdf.module
@@ -526,7 +526,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 fde291e..ffd00ef 100644
--- a/core/modules/taxonomy/taxonomy.module
+++ b/core/modules/taxonomy/taxonomy.module
@@ -302,27 +302,16 @@ 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'] = $variables['elements']['name'];
   unset($variables['elements']['name']);
   $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 2ecc713..304486b 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 964323c..8b222b8 100644
--- a/core/modules/user/user.pages.inc
+++ b/core/modules/user/user.pages.inc
@@ -108,13 +108,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';
 }
