diff --git a/core/lib/Drupal/Core/Entity/EntityViewBuilder.php b/core/lib/Drupal/Core/Entity/EntityViewBuilder.php
index 8bfb3a3..9c241cc 100644
--- a/core/lib/Drupal/Core/Entity/EntityViewBuilder.php
+++ b/core/lib/Drupal/Core/Entity/EntityViewBuilder.php
@@ -148,8 +148,6 @@ protected function getBuildDefaults(EntityInterface $entity, $view_mode) {
     $this->moduleHandler()->alter('entity_view_mode', $view_mode, $entity, $context);
 
     $build = array(
-      '#theme' => $this->entityTypeId,
-      "#{$this->entityTypeId}" => $entity,
       '#view_mode' => $view_mode,
       // Collect cache defaults for this entity.
       '#cache' => array(
@@ -159,6 +157,17 @@ protected function getBuildDefaults(EntityInterface $entity, $view_mode) {
       ),
     );
 
+    // Add the default #theme key if a template exists for it.
+    if (\Drupal::service('theme.registry')->getRuntime()->has($this->entityTypeId)) {
+      $build['#theme'] = $this->entityTypeId;
+      $build["#{$this->entityTypeId}"] = $entity;
+    }
+    else {
+      // Otherwise use the generic entity type.
+      $build['#theme'] = 'entity';
+      $build['#entity'] = $entity;
+    }
+
     // Cache the rendered output if permitted by the view mode and global entity
     // type configuration.
     if ($this->isViewModeCacheable($view_mode) && !$entity->isNew() && $entity->isDefaultRevision() && $this->entityType->isRenderCacheable()) {
diff --git a/core/modules/system/system.module b/core/modules/system/system.module
index 2f627be..d46ada6 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -17,6 +17,7 @@
 use Drupal\Core\KeyValueStore\KeyValueDatabaseExpirableFactory;
 use Drupal\Core\PageCache\RequestPolicyInterface;
 use Drupal\Core\PhpStorage\PhpStorageFactory;
+use Drupal\Core\Render\Element;
 use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\Core\Routing\StackedRouteMatchInterface;
 use Drupal\Core\Language\LanguageInterface;
@@ -217,6 +218,9 @@ function system_theme() {
       'variables' => array('menu_items' => NULL),
       'file' => 'system.admin.inc',
     ),
+    'entity' => array(
+      'render element' => 'elements',
+    ),
     'entity_add_list' => array(
       'variables' => array(
         'bundles' => array(),
@@ -248,6 +252,63 @@ function system_hook_info() {
 }
 
 /**
+ * Prepares variables for entity templates.
+ *
+ * Default template: entity.html.twig.
+ *
+ * @param array $variables
+ *   An associative array containing:
+ *   - elements: An array of elements to display in view mode.
+ */
+function template_preprocess_entity(&$variables) {
+  $variables['view_mode'] = $variables['elements']['#view_mode'];
+  $variables['entity'] = $variables['elements']['#entity'];
+  /** @var \Drupal\Core\Entity\EntityInterface $entity */
+  $entity = $variables['entity'];
+
+  $variables['url'] = $entity->toUrl('canonical', array(
+    'language' => $entity->language(),
+  ))->toString();
+
+
+  // If an element for the entity label is provided, put it into the label
+  // to make it accessible in a common way.
+  $title_key = $entity->getEntityType()->getKey('label');
+  if ($title_key && isset($variables['elements'][$title_key])) {
+    $variables['label'] = $variables['elements'][$title_key];
+    unset($variables['elements'][$title_key]);
+  }
+
+  // Helpful $content variable for templates.
+  $variables += array('content' => array());
+  foreach (Element::children($variables['elements']) as $key) {
+    $variables['content'][$key] = $variables['elements'][$key];
+  }
+}
+
+/**
+ * Implements hook_theme_suggestions_HOOK().
+ */
+function system_theme_suggestions_entity(array $variables) {
+  $suggestions = array();
+  /** @var \Drupal\Core\Entity\EntityInterface $entity */
+  $entity = $variables['elements']['#entity'];
+  $entity_type_id = $entity->getEntityTypeId();
+  $sanitized_view_mode = strtr($variables['elements']['#view_mode'], '.', '_');
+
+  $suggestions[] = 'entity__' . $entity_type_id;
+  $suggestions[] = 'entity__' . $entity_type_id . '__' . $sanitized_view_mode;
+  if ($entity->getEntityType()->hasKey('bundle')) {
+    $suggestions[] = 'entity__' . $entity_type_id . '__' . $entity->bundle();
+    $suggestions[] = 'entity__' . $entity_type_id . '__' . $entity->bundle() . '__' . $sanitized_view_mode;
+  }
+  $suggestions[] = 'entity__' . $entity_type_id . '__' .$entity->id();
+  $suggestions[] = 'entity__' . $entity_type_id . '__' .$entity->id() . '__' . $sanitized_view_mode;
+
+  return $suggestions;
+}
+
+/**
  * Implements hook_theme_suggestions_HOOK().
  */
 function system_theme_suggestions_html(array $variables) {
diff --git a/core/modules/system/templates/entity.html.twig b/core/modules/system/templates/entity.html.twig
new file mode 100644
index 0000000..50d904c
--- /dev/null
+++ b/core/modules/system/templates/entity.html.twig
@@ -0,0 +1,52 @@
+{#
+/**
+ * @file
+ * Default theme implementation to display an entity.
+ *
+ * Available variables:
+ * - entity: The entity with limited access to object properties and methods.
+ *   Only method names starting with "get", "has", or "is" and a few common
+ *   methods such as "id", "label", and "bundle" are available. For example:
+ *   - entity.getEntityTypeId() will return the entity type ID.
+ *   - entity.hasField('field_example') returns TRUE if the entity includes
+ *     field_example. (This does not indicate the presence of a value in this
+ *     field.)
+ *   Calling other methods, such as entity.delete(), will result in an exception.
+ *   See \Drupal\Core\Entity\EntityInterface for a full list of methods.
+ * - label: The title of the entity.
+ * - content: All rendered field items. Use {{ content }} to print them all,
+ *   or print a subset such as {{ content.field_example }}. Use
+ *   {{ content|without('field_example') }} to temporarily suppress the printing
+ *   of a given child element.
+ * - url: Direct URL of the current entity.
+ * - attributes: HTML attributes for the containing element.
+ * - title_attributes: Same as attributes, except applied to the main title
+ *   tag that appears in the template.
+ * - content_attributes: Same as attributes, except applied to the main
+ *   content tag that appears in the template.
+ * - 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.
+ * - view_mode: View mode; for example, "teaser" or "full".
+ *
+ * @see template_preprocess_entity()
+ *
+ * @ingroup themeable
+ */
+#}
+<article{{ attributes }}>
+
+  {{ title_prefix }}
+  {% if label %}
+    <h2{{ title_attributes }}>
+      <a href="{{ url }}" rel="bookmark">{{ label }}</a>
+    </h2>
+  {% endif %}
+  {{ title_suffix }}
+
+  <div{{ content_attributes }}>
+    {{ content }}
+  </div>
+
+</article>
