diff --git a/core/lib/Drupal/Core/Entity/Controller/EntityViewController.php b/core/lib/Drupal/Core/Entity/Controller/EntityViewController.php
new file mode 100644
index 0000000..b9667d2
--- /dev/null
+++ b/core/lib/Drupal/Core/Entity/Controller/EntityViewController.php
@@ -0,0 +1,69 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Entity\Controller\EntityViewController.
+ */
+
+namespace Drupal\Core\Entity\Controller;
+
+use Drupal\Core\Controller\ControllerInterface;
+use Drupal\Core\Entity\EntityManager;
+use Drupal\Core\Entity\EntityInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Defines a generic controller to render a single entity.
+ */
+class EntityViewController implements ControllerInterface {
+
+  /**
+   * The entity manager
+   *
+   * @var \Drupal\Core\Entity\EntityManager
+   */
+  protected $entityManager;
+
+  /**
+   * Creates an EntityListController object.
+   *
+   * @param \Drupal\Core\Entity\EntityManager $entity_manager
+   *   The entity manager.
+   */
+  public function __construct(EntityManager $entity_manager) {
+    $this->entityManager = $entity_manager;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container) {
+    return new static(
+      $container->get('plugin.manager.entity')
+    );
+  }
+
+  /**
+   * Provides a page to render a single entity.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $_entity
+   *   The Entity to be rendered. Note this variable is named $_entity rather
+   *   than $entity to prevent collisions with other named placeholders in the
+   *   route.
+   * @param string $view_mode
+   *   (optional) The view mode that should be used to display the entity.
+   *   Defaults to 'full'.
+   * @param string $langcode
+   *   (optional) For which language the entity should be rendered, defaults to
+   *   the current content language.
+   *
+   * @return array
+   *   A render array as expected by drupal_render().
+   */
+  public function view(EntityInterface $_entity, $view_mode = 'full', $langcode = NULL) {
+    return $this->entityManager
+      ->getRenderController($_entity->entityType())
+      ->view($_entity, $view_mode, $langcode);
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Entity/Enhancer/EntityRouteEnhancer.php b/core/lib/Drupal/Core/Entity/Enhancer/EntityRouteEnhancer.php
index f2f6648..2cf8d47 100644
--- a/core/lib/Drupal/Core/Entity/Enhancer/EntityRouteEnhancer.php
+++ b/core/lib/Drupal/Core/Entity/Enhancer/EntityRouteEnhancer.php
@@ -9,6 +9,7 @@
 
 use Symfony\Component\HttpFoundation\Request;
 use Symfony\Cmf\Component\Routing\Enhancer\RouteEnhancerInterface;
+use Symfony\Cmf\Component\Routing\RouteObjectInterface;
 use Drupal\Core\ContentNegotiation;
 
 /**
@@ -47,6 +48,54 @@ public function enhance(array $defaults, Request $request) {
         $defaults['entity_type'] = $defaults['_entity_list'];
         unset($defaults['_entity_list']);
       }
+      elseif (!empty($defaults['_entity_view'])) {
+        $defaults['_controller'] = 'controller.page:content';
+        $defaults['_content'] = '\Drupal\Core\Entity\Controller\EntityViewController::view';
+        if (strpos($defaults['_entity_view'], '.') !== FALSE) {
+          // The _entity_view entry is of the form entity_type.view_mode.
+          list($entity_type, $view_mode) = explode('.', $defaults['_entity_view']);
+          $defaults['view_mode'] = $view_mode;
+        }
+        else {
+          // Only the entity type is nominated, the view mode will use the
+          // default.
+          $entity_type = $defaults['_entity_view'];
+        }
+        // Set by reference so that we get the upcast value.
+        if (!empty($defaults[$entity_type])) {
+          $defaults['_entity'] = &$defaults[$entity_type];
+        }
+        else {
+          // The entity is not keyed by its entity_type. Attempt to find it
+          // using a converter.
+          $route = $defaults[RouteObjectInterface::ROUTE_OBJECT];
+          if ($route && is_object($route)) {
+            $options = $route->getOptions();
+            if (isset($options['parameters'])) {
+              foreach ($options['parameters'] as $name => $details) {
+                if (!empty($details['type'])) {
+                  $type = $details['type'];
+                  // Type is of the form entity:{entity_type}.
+                  $parameter_entity_type = substr($type, strlen('entity:'));
+                  if ($entity_type == $parameter_entity_type) {
+                    // We have the matching entity type. Set the '_entity' key
+                    // to point to this named placeholder. The entity in this
+                    // position is the one being rendered.
+                    $defaults['_entity'] = &$defaults[$name];
+                  }
+                }
+              }
+            }
+            else {
+              throw new \RuntimeException(sprintf('Failed to find entity of type %s in route named %s', $entity_type, $defaults[RouteObjectInterface::ROUTE_NAME]));
+            }
+          }
+          else {
+            throw new \RuntimeException(sprintf('Failed to find entity of type %s in route named %s', $entity_type, $defaults[RouteObjectInterface::ROUTE_NAME]));
+          }
+        }
+        unset($defaults['_entity_view']);
+      }
     }
     return $defaults;
   }
diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityViewControllerTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityViewControllerTest.php
new file mode 100644
index 0000000..502a206
--- /dev/null
+++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityViewControllerTest.php
@@ -0,0 +1,71 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\system\Tests\Entity\EntityViewControllerTest.
+ */
+
+namespace Drupal\system\Tests\Entity;
+
+use Drupal\simpletest\WebTestBase;
+use Drupal\Core\Language\Language;
+
+/**
+ * Tests \Drupal\Core\Entity\Controller\EntityViewController.
+ */
+class EntityViewControllerTest extends WebTestBase {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = array('entity_test');
+
+  /**
+   * Array of test entities.
+   *
+   * @var array
+   */
+  protected $entities = array();
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Entity View Controller',
+      'description' => 'Tests EntityViewController functionality.',
+      'group' => 'Entity API',
+    );
+  }
+
+  function setUp() {
+    parent::setUp();
+    // Create some dummy entity_test_render entities.
+    for ($i = 0; $i < 2; $i++) {
+      $random_label = $this->randomName();
+      $data = array('bundle' => 'entity_test_render', 'name' => $random_label);
+      $entity_test = $this->container->get('plugin.manager.entity')->getStorageController('entity_test_render')->create($data);
+      $entity_test->save();
+      $this->entities[] = $entity_test;
+    }
+
+  }
+
+  /**
+   * Tests EntityViewController.
+   */
+  function testEntityViewController() {
+    foreach ($this->entities as $entity) {
+      $this->drupalGet('entity-test-render/' . $entity->id());
+      $this->assertRaw($entity->label());
+      $this->assertRaw('full');
+
+      $this->drupalGet('entity-test-render-converter/' . $entity->id());
+      $this->assertRaw($entity->label());
+      $this->assertRaw('full');
+
+      $this->drupalGet('entity-test-render-no-view-mode/' . $entity->id());
+      $this->assertRaw($entity->label());
+      $this->assertRaw('full');
+    }
+  }
+}
diff --git a/core/modules/system/tests/modules/entity_test/entity_test.routing.yml b/core/modules/system/tests/modules/entity_test/entity_test.routing.yml
new file mode 100644
index 0000000..645fae1
--- /dev/null
+++ b/core/modules/system/tests/modules/entity_test/entity_test.routing.yml
@@ -0,0 +1,24 @@
+entity_test_render:
+  pattern: '/entity-test-render/{entity_test_render}'
+  defaults:
+    _entity_view: 'entity_test_render.full'
+  requirements:
+    _access: 'TRUE'
+
+entity_test_render_options:
+  pattern: '/entity-test-render-converter/{foo}'
+  options:
+    parameters:
+      foo:
+        type: 'entity:entity_test_render'
+  defaults:
+    _entity_view: 'entity_test_render.full'
+  requirements:
+    _access: 'TRUE'
+
+entity_test_render_no_view_mode:
+  pattern: '/entity-test-render-no-view-mode/{entity_test_render}'
+  defaults:
+    _entity_view: 'entity_test_render'
+  requirements:
+    _access: 'TRUE'
diff --git a/core/tests/Drupal/Tests/Core/Entity/Controller/EntityViewControllerTest.php b/core/tests/Drupal/Tests/Core/Entity/Controller/EntityViewControllerTest.php
new file mode 100644
index 0000000..cfa1e29
--- /dev/null
+++ b/core/tests/Drupal/Tests/Core/Entity/Controller/EntityViewControllerTest.php
@@ -0,0 +1,62 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Tests\Core\Entity\Controller\EntityViewControllerTest.
+ */
+
+namespace Drupal\Core\Tests\Entity\Controller;
+
+use Drupal\Core\Entity\Controller\EntityViewController;
+use Drupal\Tests\UnitTestCase;
+
+/**
+ * Tests the entity view controller.
+ *
+ * @see \Drupal\Core\Entity\Controller\EntityViewController
+ */
+class EntityViewControllerTest extends UnitTestCase{
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Entity route enhancer test',
+      'description' => 'Tests the entity route enhancer.',
+      'group' => 'Entity'
+    );
+  }
+
+  /**
+   * Tests the enhancer method.
+   *
+   * @see \Drupal\Core\Entity\Controller\EntityViewController::view()
+   */
+  public function testView() {
+
+    // Mock a render controller.
+    $render_controller = $this->getMockBuilder('Drupal\entity_test\EntityTestRenderController')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $render_controller->expects($this->any())
+      ->method('view')
+      ->will($this->returnValue('Output from rendering the entity'));
+
+    // Mock an entity manager.
+    $entity_manager = $this->getMockBuilder('Drupal\Core\Entity\EntityManager')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $entity_manager->expects($this->any())
+      ->method('getRenderController')
+      ->will($this->returnValue($render_controller));
+
+    // Mock an 'entity_test_render' entity.
+    $entity = $this->getMockBuilder('Drupal\entity_test\Plugin\Core\Entity\EntityTestRender')
+      ->disableOriginalConstructor()
+      ->getMock();
+
+    // Initialize the controller to test.
+    $controller = new EntityViewController($entity_manager);
+
+    // Test the view method.
+    $this->assertEquals($controller->view($entity, 'full'), 'Output from rendering the entity');
+  }
+}
diff --git a/core/tests/Drupal/Tests/Core/Entity/Enhancer/EntityRouteEnhancerTest.php b/core/tests/Drupal/Tests/Core/Entity/Enhancer/EntityRouteEnhancerTest.php
index ffd60a1..17f454e 100644
--- a/core/tests/Drupal/Tests/Core/Entity/Enhancer/EntityRouteEnhancerTest.php
+++ b/core/tests/Drupal/Tests/Core/Entity/Enhancer/EntityRouteEnhancerTest.php
@@ -10,6 +10,7 @@
 use Drupal\Core\ContentNegotiation;
 use Drupal\Core\Entity\Enhancer\EntityRouteEnhancer;
 use Drupal\Tests\UnitTestCase;
+use Symfony\Cmf\Component\Routing\RouteObjectInterface;
 use Symfony\Component\HttpFoundation\Request;
 
 /**
@@ -62,6 +63,52 @@ public function testEnhancer() {
     $this->assertEquals('\Drupal\Core\Entity\Controller\EntityListController::listing', $defaults['_content'], 'The entity list controller was not set.');
     $this->assertEquals('entity_test.default', $defaults['entity_type']);
     $this->assertFalse(isset($defaults['_entity_list']));
+
+    // Set _entity_view and ensure that the entity view controller is set.
+    $defaults = array();
+    $defaults['_entity_view'] = 'entity_test.full';
+    $defaults['entity_test'] = 'Mock entity';
+    $defaults = $route_enhancer->enhance($defaults, $request);
+    $this->assertEquals('controller.page:content', $defaults['_controller']);
+    $this->assertEquals('\Drupal\Core\Entity\Controller\EntityViewController::view', $defaults['_content'], 'The entity view controller was not set.');
+    $this->assertEquals($defaults['_entity'], 'Mock entity');
+    $this->assertEquals($defaults['view_mode'], 'full');
+    $this->assertFalse(isset($defaults['_entity_view']));
+
+    // Set _entity_view and ensure that the entity view controller is set using
+    // a converter.
+    $defaults = array();
+    $defaults['_entity_view'] = 'entity_test.full';
+    $defaults['foo'] = 'Mock entity';
+    // Add a converter.
+    $options['parameters']['foo'] = array('type' => 'entity:entity_test');
+    // Set the route.
+    $route = $this->getMockBuilder('Symfony\Component\Routing\Route')
+      ->disableOriginalConstructor()
+      ->getMock();
+
+    $route->expects($this->any())
+      ->method('getOptions')
+      ->will($this->returnValue($options));
+
+    $defaults[RouteObjectInterface::ROUTE_OBJECT] = $route;
+    $defaults = $route_enhancer->enhance($defaults, $request);
+    $this->assertEquals('controller.page:content', $defaults['_controller']);
+    $this->assertEquals('\Drupal\Core\Entity\Controller\EntityViewController::view', $defaults['_content'], 'The entity view controller was not set.');
+    $this->assertEquals($defaults['_entity'], 'Mock entity');
+    $this->assertEquals($defaults['view_mode'], 'full');
+    $this->assertFalse(isset($defaults['_entity_view']));
+
+    // Set _entity_view without a view mode.
+    $defaults = array();
+    $defaults['_entity_view'] = 'entity_test';
+    $defaults['entity_test'] = 'Mock entity';
+    $defaults = $route_enhancer->enhance($defaults, $request);
+    $this->assertEquals('controller.page:content', $defaults['_controller']);
+    $this->assertEquals('\Drupal\Core\Entity\Controller\EntityViewController::view', $defaults['_content'], 'The entity view controller was not set.');
+    $this->assertEquals($defaults['_entity'], 'Mock entity');
+    $this->assertTrue(empty($defaults['view_mode']));
+    $this->assertFalse(isset($defaults['_entity_view']));
   }
 
 }
