diff --git a/core/lib/Drupal/Core/Url.php b/core/lib/Drupal/Core/Url.php
index 999f447..2c970a7 100644
--- a/core/lib/Drupal/Core/Url.php
+++ b/core/lib/Drupal/Core/Url.php
@@ -15,6 +15,7 @@
 use Drupal\Core\Utility\UnroutedUrlAssemblerInterface;
 use Symfony\Cmf\Component\Routing\RouteObjectInterface;
 use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\Routing\Exception\RouteNotFoundException;
 
 /**
  * Defines an object that holds information about a URL.
@@ -196,9 +197,15 @@ public static function fromRouteMatch(RouteMatchInterface $route_match) {
    * base://robots.txt. For URLs that have Drupal routes (that is, most pages
    * generated by Drupal), use Url::fromRoute().
    *
+   * For resolving URLs to an entity, you may use the
+   * entity://{entity_type}/{entity_id} scheme. For example entity://node/1
+   * would resolve to the entity.node.canonical route with a node parameter of
+   * one.
+   *
    * @param string $uri
    *   The URI of the external resource including the scheme. For Drupal paths
    *   that are not handled by the routing system, use base:// for the scheme.
+   *   For entity URLs you may use entity://{entity_type}/{entity_id}.
    * @param array $options
    *   (optional) An associative array of additional URL options, with the
    *   following elements:
@@ -217,7 +224,7 @@ public static function fromRouteMatch(RouteMatchInterface $route_match) {
    *     respectively. TRUE enforces HTTPS and FALSE enforces HTTP.
    *
    * @return \Drupal\Core\Url
-   *   A new Url object for an unrouted (non-Drupal) URL.
+   *   A new Url object for an unrouted (non-Drupal) URL or a routed entity URI.
    *
    * @throws \InvalidArgumentException
    *   Thrown when the passed in path has no scheme.
@@ -225,10 +232,15 @@ public static function fromRouteMatch(RouteMatchInterface $route_match) {
    * @see static::fromRoute()
    */
   public static function fromUri($uri, $options = array()) {
-    if (!parse_url($uri, PHP_URL_SCHEME)) {
+    if (!($scheme = parse_url($uri, PHP_URL_SCHEME))) {
       throw new \InvalidArgumentException(String::format('The URI "@uri" is invalid. You must use a valid URI scheme. Use base:// for a path, e.g., to a Drupal file that needs the base path. Do not use this for internal paths controlled by Drupal.', ['@uri' => $uri]));
     }
 
+    // Special case entity:// URIs. Map these to the canonical entity route.
+    if ($scheme === 'entity') {
+      return static::fromEntityUri($uri);
+    }
+
     $url = new static($uri, array(), $options);
     $url->setUnrouted();
 
@@ -236,6 +248,42 @@ public static function fromUri($uri, $options = array()) {
   }
 
   /**
+   * Create a new Url object for entity URIs.
+   *
+   * @param string $uri
+   *   An URI of the form entity://{entity_type}/{entity_id}.
+   *
+   * @return \Drupal\Core\Url
+   *   A new Url object for an entity's canonical route.
+   *
+   * @throws \InvalidArgumentException
+   *   Thrown when the entity URI is invalid or the entity does not have a valid
+   *   canonical link template.
+   * @throws \Symfony\Component\Routing\Exception\RouteNotFoundException
+   *   Thrown when the entity's canonical route does not exist.
+   */
+  protected static function fromEntityUri($uri) {
+    $uri_parts = parse_url($uri);
+    $entity_type_id = $uri_parts['host'];
+    $entity_id = trim($uri_parts['path'], '/');
+    if ($uri_parts['scheme'] != 'entity' || $entity_id === '') {
+      throw new \InvalidArgumentException(String::format('The entity URI "@uri" is invalid. You must specify the entity id in the URL. e.g., entity://node/1 for loading the canonical path to node entity with id 1.',
+        ['@uri' => $uri]));
+    }
+
+    $entity_type = \Drupal::entityManager()->getDefinition($entity_type_id);
+    if (!$entity_type->hasLinkTemplate('canonical')) {
+      throw new \InvalidArgumentException(String::format('The entity type "@entity_type_id" does not have a "canonical" link template.', ['@entity_type_id' => $entity_type_id]));
+    }
+
+    $url = new static("entity.$entity_type_id.canonical", [$entity_type_id => $entity_id]);
+    // Validate the route exists, ::toString() will throw a
+    // RouteNotFoundException if the route does not exist.
+    $url->toString();
+    return $url;
+  }
+
+  /**
    * Returns the Url object matching a request.
    *
    * SECURITY NOTE: The request path is not checked to be valid and accessible
diff --git a/core/tests/Drupal/Tests/Core/UrlTest.php b/core/tests/Drupal/Tests/Core/UrlTest.php
index cea8770..1bff90d 100644
--- a/core/tests/Drupal/Tests/Core/UrlTest.php
+++ b/core/tests/Drupal/Tests/Core/UrlTest.php
@@ -9,13 +9,16 @@
 
 use Drupal\Core\Access\AccessManagerInterface;
 use Drupal\Core\DependencyInjection\ContainerBuilder;
+use Drupal\Core\Entity\EntityType;
 use Drupal\Core\Routing\RouteMatch;
 use Drupal\Core\Url;
 use Drupal\Tests\UnitTestCase;
 use Symfony\Cmf\Component\Routing\RouteObjectInterface;
 use Symfony\Component\HttpFoundation\ParameterBag;
 use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\Routing\Exception\InvalidParameterException;
 use Symfony\Component\Routing\Exception\ResourceNotFoundException;
+use Symfony\Component\Routing\Exception\RouteNotFoundException;
 use Symfony\Component\Routing\Route;
 
 /**
@@ -51,6 +54,13 @@ class UrlTest extends UnitTestCase {
   protected $router;
 
   /**
+   * The route provider.
+   *
+   * @var \Drupal\Tests\Core\Routing\TestRouterInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $routeProvider;
+
+  /**
    * An array of values to use for the test.
    *
    * @var array
@@ -58,6 +68,13 @@ class UrlTest extends UnitTestCase {
   protected $map;
 
   /**
+   * The entity manager.
+   *
+   * @var \Drupal\Core\Entity\EntityManagerInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $entityManager;
+
+  /**
    * {@inheritdoc}
    */
   protected function setUp() {
@@ -90,10 +107,15 @@ protected function setUp() {
       ->will($this->returnValueMap($alias_map));
 
     $this->router = $this->getMock('Drupal\Tests\Core\Routing\TestRouterInterface');
+    $this->routeProvider = $this->getMock('Symfony\Cmf\Component\Routing\RouteProviderInterface');
+    $this->entityManager = $this->getMock('Drupal\Core\Entity\EntityManagerInterface');
+
     $this->container = new ContainerBuilder();
     $this->container->set('router.no_access_checks', $this->router);
+    $this->container->set('router.route_provider', $this->routeProvider);
     $this->container->set('url_generator', $this->urlGenerator);
     $this->container->set('path.alias_manager', $this->pathAliasManager);
+    $this->container->set('entity.manager', $this->entityManager);
     \Drupal::setContainer($this->container);
   }
 
@@ -441,6 +463,94 @@ public function testFromRouteMatch() {
   }
 
   /**
+   * Tests the fromUri() method with an entity:// URI.
+   *
+   * @covers ::fromUri
+   */
+  public function testEntityUris() {
+    $entity_type = new EntityType(['id' => 'test_entity', 'links' => ['canonical' => '/test_entity/{test_entity}']]);
+    $this->entityManager->expects($this->any())
+      ->method('getDefinition')
+      ->willReturn($entity_type);
+
+    $map = [];
+    $map[] = [['entity.test_entity.canonical'], ['test_entity/1']];
+
+    $this->routeProvider->expects($this->any())
+      ->method('getRoutesByNames')
+      ->will($this->returnValueMap($map));
+
+    $uri = 'entity://test_entity/1';
+    $url = Url::fromUri($uri);
+    $this->assertSame('entity.test_entity.canonical', $url->getRouteName());
+    $this->assertEquals(['test_entity' => '1'], $url->getRouteParameters());
+  }
+
+  /**
+   * Tests the fromUri() method with an invalid entity:// URI.
+   *
+   * @covers ::fromUri
+   * @expectedException \Symfony\Component\Routing\Exception\RouteNotFoundException
+   */
+  public function testInvalidEntityUriRoute() {
+    $entity_type = new EntityType(['id' => 'invalid_entity', 'links' => ['canonical' => '/example/{example}']]);
+    $this->entityManager->expects($this->any())
+      ->method('getDefinition')
+      ->willReturn($entity_type);
+
+    // Make the mocked URL generator behave like the actual one.
+    $this->urlGenerator->expects($this->once())
+      ->method('generateFromRoute')
+      ->with('entity.invalid_entity.canonical', ['invalid_entity' => 1])
+      ->willThrowException(new RouteNotFoundException('Route "entity.invalid_entity.canonical" does not exist.'));
+
+    $uri = 'entity://invalid_entity/1';
+    Url::fromUri($uri);
+  }
+
+  /**
+   * Tests the fromUri() method with a missing canonical link template.
+   *
+   * @covers ::fromUri
+   * @expectedException \InvalidArgumentException
+   */
+  public function testInvalidEntityUriWithMissingCanonicalLinkTemplate() {
+    $entity_type = new EntityType(['id' => 'test_entity']);
+    $this->entityManager->expects($this->any())
+      ->method('getDefinition')
+      ->willReturn($entity_type);
+
+    // Make the mocked URL generator behave like the actual one.
+    $this->urlGenerator->expects($this->never())
+      ->method('generateFromRoute');
+
+    $uri = 'entity://test_entity/1';
+    Url::fromUri($uri);
+  }
+
+  /**
+   * Tests the fromUri() method with an invalid entity:// URI.
+   *
+   * @covers ::fromUri
+   * @expectedException \Symfony\Component\Routing\Exception\InvalidParameterException
+   */
+  public function testInvalidEntityUriParameter() {
+    $entity_type = new EntityType(['id' => 'example', 'links' => ['canonical' => '/example/{example}']]);
+    $this->entityManager->expects($this->any())
+      ->method('getDefinition')
+      ->willReturn($entity_type);
+
+    // Make the mocked URL generator behave like the actual one.
+    $this->urlGenerator->expects($this->once())
+      ->method('generateFromRoute')
+      ->with('entity.test_entity.canonical', ['test_entity' => '1/blah'])
+      ->willThrowException(new InvalidParameterException('Parameter "test_entity" for route "/test_entity/{test_entity}" must match "[^/]++" ("1/blah" given) to generate a corresponding URL..'));
+
+    $uri = 'entity://test_entity/1/blah';
+    Url::fromUri($uri);
+  }
+
+  /**
    * Creates a mock access manager for the access tests.
    *
    * @param bool $access
