diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php b/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php
index ab2fb10..bb396e6 100644
--- a/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php
+++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php
@@ -387,6 +387,7 @@ public function urlInfo($rel = 'edit-form', array $options = []) {
    * {@inheritdoc}
    */
   public function url($rel = 'edit-form', $options = array()) {
+    // Do not remove this override: the default value of $rel is different.
     return parent::url($rel, $options);
   }
 
@@ -394,12 +395,22 @@ public function url($rel = 'edit-form', $options = array()) {
    * {@inheritdoc}
    */
   public function link($text = NULL, $rel = 'edit-form', array $options = []) {
+    // Do not remove this override: the default value of $rel is different.
     return parent::link($text, $rel, $options);
   }
 
   /**
    * {@inheritdoc}
    */
+  public function toUrl($rel = 'edit-form', array $options = []) {
+    // Unless language was already provided, avoid setting an explicit language.
+    $options += ['language' => NULL];
+    return parent::toUrl($rel, $options);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function getCacheTagsToInvalidate() {
     // Use cache tags that match the underlying config object's name.
     // @see \Drupal\Core\Config\ConfigBase::getCacheTags()
diff --git a/core/lib/Drupal/Core/Entity/Entity.php b/core/lib/Drupal/Core/Entity/Entity.php
index 3ea549d..8164d7c 100644
--- a/core/lib/Drupal/Core/Entity/Entity.php
+++ b/core/lib/Drupal/Core/Entity/Entity.php
@@ -173,6 +173,13 @@ public function label() {
    * {@inheritdoc}
    */
   public function urlInfo($rel = 'canonical', array $options = []) {
+    return $this->toUrl($rel, $options);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function toUrl($rel = 'canonical', array $options = []) {
     if ($this->id() === NULL) {
       throw new EntityMalformedException(sprintf('The "%s" entity cannot have a URI as it does not have an ID', $this->getEntityTypeId()));
     }
@@ -252,26 +259,33 @@ protected function linkTemplates() {
    * {@inheritdoc}
    */
   public function link($text = NULL, $rel = 'canonical', array $options = []) {
-    if (is_null($text)) {
+    return $this->toLink($text, $rel, $options)->toString();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function toLink($text = NULL, $rel = 'canonical', array $options = []) {
+    if (!isset($text)) {
       $text = $this->label();
     }
-    $url = $this->urlInfo($rel);
+    $url = $this->toUrl($rel);
     $options += $url->getOptions();
     $url->setOptions($options);
-    return (new Link($text, $url))->toString();
+    return new Link($text, $url);
   }
 
   /**
    * {@inheritdoc}
    */
   public function url($rel = 'canonical', $options = array()) {
-    // While self::urlInfo() will throw an exception if the entity is new,
+    // While self::toUrl() will throw an exception if the entity has no id,
     // the expected result for a URL is always a string.
-    if ($this->isNew() || !$this->hasLinkTemplate($rel)) {
+    if ($this->id() === NULL || !$this->hasLinkTemplate($rel)) {
       return '';
     }
 
-    $uri = $this->urlInfo($rel);
+    $uri = $this->toUrl($rel);
     $options += $uri->getOptions();
     $uri->setOptions($options);
     return $uri->toString();
diff --git a/core/lib/Drupal/Core/Entity/EntityInterface.php b/core/lib/Drupal/Core/Entity/EntityInterface.php
index 1f476e5..62a8f44 100644
--- a/core/lib/Drupal/Core/Entity/EntityInterface.php
+++ b/core/lib/Drupal/Core/Entity/EntityInterface.php
@@ -101,7 +101,29 @@ public function bundle();
   public function label();
 
   /**
-   * Gets the URI elements of the entity.
+   * Gets the URL object for the entity.
+   *
+   * @param string $rel
+   *   The link relationship type, for example: canonical or edit-form.
+   * @param array $options
+   *   See \Drupal\Core\Routing\UrlGeneratorInterface::generateFromRoute() for
+   *   the available options.
+   *
+   * @return \Drupal\Core\Url
+   *   The URL object.
+   *
+   * @deprecated in Drupal 8.0.0, intended to be removed in Drupal 9.0.0
+   *   Use toUrl() instead.
+   *
+   * @see \Drupal\Core\Entity\EntityInterface::toUrl
+   */
+  public function urlInfo($rel = 'canonical', array $options = array());
+
+  /**
+   * Gets the URL object for the entity.
+   *
+   * The entity must have an id already. Content entities usually get their IDs
+   * by saving them.
    *
    * URI templates might be set in the links array in an annotation, for
    * example:
@@ -128,8 +150,12 @@ public function label();
    *   the available options.
    *
    * @return \Drupal\Core\Url
+   *   The URL object.
+   *
+   * @throws \Drupal\Core\Entity\EntityMalformedException
+   * @throws \Drupal\Core\Entity\Exception\UndefinedLinkTemplateException
    */
-  public function urlInfo($rel = 'canonical', array $options = array());
+  public function toUrl($rel = 'canonical', array $options = array());
 
   /**
    * Gets the public URL for this entity.
@@ -142,10 +168,37 @@ public function urlInfo($rel = 'canonical', array $options = array());
    *
    * @return string
    *   The URL for this entity.
+   *
+   * @deprecated in Drupal 8.0.0, intended to be removed in Drupal 9.0.0
+   *   Please use toUrl() instead.
+   *
+   * @see \Drupal\Core\Entity\EntityInterface::toUrl
    */
   public function url($rel = 'canonical', $options = array());
 
   /**
+   * Deprecated way of generating a link to the entity. See toLink().
+   *
+   * @param string|null $text
+   *   (optional) The link text for the anchor tag as a translated string.
+   *   If NULL, it will use the entity's label. Defaults to NULL.
+   * @param string $rel
+   *   (optional) The link relationship type. Defaults to 'canonical'.
+   * @param array $options
+   *   See \Drupal\Core\Routing\UrlGeneratorInterface::generateFromRoute() for
+   *   the available options.
+   *
+   * @return string
+   *   An HTML string containing a link to the entity.
+   *
+   * @deprecated in Drupal 8.0.0, intended to be removed in Drupal 9.0.0
+   *   Please use toLink() instead.
+   *
+   * @see \Drupal\Core\Entity\EntityInterface::toLink
+   */
+  public function link($text = NULL, $rel = 'canonical', array $options = []);
+
+  /**
    * Generates the HTML for a link to this entity.
    *
    * @param string|null $text
@@ -157,10 +210,13 @@ public function url($rel = 'canonical', $options = array());
    *   See \Drupal\Core\Routing\UrlGeneratorInterface::generateFromRoute() for
    *   the available options.
    *
-   * @return string
-   *   An HTML string containing a link to the entity.
+   * @return \Drupal\Core\Link
+   *   A Link to the entity.
+   *
+   * @throws \Drupal\Core\Entity\EntityMalformedException
+   * @throws \Drupal\Core\Entity\Exception\UndefinedLinkTemplateException
    */
-  public function link($text = NULL, $rel = 'canonical', array $options = []);
+  public function toLink($text = NULL, $rel = 'canonical', array $options = []);
 
   /**
    * Indicates if a link template exists for a given key.
diff --git a/core/modules/views_ui/src/ViewUI.php b/core/modules/views_ui/src/ViewUI.php
index 47b8e88..fe3198b 100644
--- a/core/modules/views_ui/src/ViewUI.php
+++ b/core/modules/views_ui/src/ViewUI.php
@@ -1034,6 +1034,13 @@ public function urlInfo($rel = 'edit-form', array $options = []) {
   /**
    * {@inheritdoc}
    */
+  public function toUrl($rel = 'edit-form', array $options = []) {
+    return $this->storage->toUrl($rel, $options);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function link($text = NULL, $rel = 'edit-form', array $options = []) {
     return $this->storage->link($text, $rel, $options);
   }
@@ -1041,6 +1048,13 @@ public function link($text = NULL, $rel = 'edit-form', array $options = []) {
   /**
    * {@inheritdoc}
    */
+  public function toLink($text = NULL, $rel = 'edit-form', array $options = []) {
+    return $this->storage->toLink($text, $rel, $options);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function label() {
     return $this->storage->label();
   }
diff --git a/core/tests/Drupal/Tests/Core/Entity/EntityLinkTest.php b/core/tests/Drupal/Tests/Core/Entity/EntityLinkTest.php
index 9e54ebe..efcf1b8 100644
--- a/core/tests/Drupal/Tests/Core/Entity/EntityLinkTest.php
+++ b/core/tests/Drupal/Tests/Core/Entity/EntityLinkTest.php
@@ -57,6 +57,8 @@ protected function setUp() {
   }
 
   /**
+   * Tests for the Entity::link() method
+   *
    * @covers ::link
    *
    * @dataProvider providerTestLink
@@ -98,7 +100,7 @@ public function testLink($entity_label, $link_text, $expected_text, $link_rel =
     /** @var \Drupal\Core\Entity\Entity $entity */
     $entity = $this->getMockForAbstractClass('Drupal\Core\Entity\Entity', [
       ['id' => $entity_id, 'label' => $entity_label, 'langcode' => 'es'],
-      $entity_type_id
+      $entity_type_id,
     ]);
 
     $expected_link = Link::createFromRoute(
@@ -117,6 +119,64 @@ public function testLink($entity_label, $link_text, $expected_text, $link_rel =
   }
 
   /**
+   * Tests for the Entity::toLink() method
+   *
+   * @covers ::toLink
+   *
+   * @dataProvider providerTestLink
+   */
+  public function testToLink($entity_label, $link_text, $expected_text, $link_rel = 'canonical', array $link_options = []) {
+    $language = new Language(['id' => 'es']);
+    $link_options += ['language' => $language];
+    $this->languageManager->expects($this->any())
+      ->method('getLanguage')
+      ->with('es')
+      ->willReturn($language);
+
+    $route_name_map = [
+      'canonical' => 'entity.test_entity_type.canonical',
+      'edit-form' => 'entity.test_entity_type.edit_form',
+    ];
+    $route_name = $route_name_map[$link_rel];
+    $entity_id = 'test_entity_id';
+    $entity_type_id = 'test_entity_type';
+    $expected = '<a href="/test_entity_type/test_entity_id">' . $expected_text . '</a>';
+
+    $entity_type = $this->getMock('Drupal\Core\Entity\EntityTypeInterface');
+    $entity_type->expects($this->once())
+      ->method('getLinkTemplates')
+      ->willReturn($route_name_map);
+    $entity_type->expects($this->any())
+      ->method('getKey')
+      ->willReturnMap([
+        ['label', 'label'],
+        ['langcode', 'langcode'],
+      ]);
+
+    $this->entityManager
+      ->expects($this->any())
+      ->method('getDefinition')
+      ->with($entity_type_id)
+      ->will($this->returnValue($entity_type));
+
+    /** @var \Drupal\Core\Entity\Entity $entity */
+    $entity = $this->getMockForAbstractClass('Drupal\Core\Entity\Entity', [
+      ['id' => $entity_id, 'label' => $entity_label, 'langcode' => 'es'],
+      $entity_type_id,
+    ]);
+
+    $expected_link = Link::createFromRoute(
+      $expected_text,
+      $route_name,
+      [$entity_type_id => $entity_id],
+      ['entity_type' => $entity_type_id, 'entity' => $entity] + $link_options
+    );
+
+    $result_link = $entity->toLink($link_text, $link_rel, $link_options);
+    $this->assertEquals($expected_link, $result_link);
+  }
+
+  /**
    * Provides test data for testLink().
    */
   public function providerTestLink() {
diff --git a/core/tests/Drupal/Tests/Core/Entity/EntityUrlTest.php b/core/tests/Drupal/Tests/Core/Entity/EntityUrlTest.php
index d19f473..c60a18f 100644
--- a/core/tests/Drupal/Tests/Core/Entity/EntityUrlTest.php
+++ b/core/tests/Drupal/Tests/Core/Entity/EntityUrlTest.php
@@ -28,6 +28,8 @@ class EntityUrlTest extends UnitTestCase {
   protected $entityManager;
 
   /**
+   * The mocked URL generator.
+   *
    * @var \Drupal\Core\Routing\UrlGeneratorInterface|\PHPUnit_Framework_MockObject_MockObject
    */
   protected $urlGenerator;
@@ -50,12 +52,15 @@ protected function setUp() {
   /**
    * Tests the urlInfo() method.
    *
+   * Note that urlInfo() is a deprecated alias for toUrl().
+   * See testToUrl().
+   *
    * @covers ::urlInfo
    *
-   * @dataProvider providerTestUrlInfo
+   * @dataProvider providerTestToUrl
    */
   public function testUrlInfo($entity_class, $link_template, $expected, $langcode = NULL) {
-    /** @var $entity \Drupal\Core\Entity\EntityInterface */
+    /** @var \Drupal\Core\Entity\EntityInterface $entity */
     $entity = $this->getMockForAbstractClass($entity_class, array(array('id' => 'test_entity_id'), 'test_entity_type'));
     $uri = $this->getTestUrlInfo($entity, $link_template, [], $langcode);
 
@@ -75,27 +80,57 @@ public function testUrlInfo($entity_class, $link_template, $expected, $langcode
       }
     }
   }
+  /**
+   * Tests the toUrl() method.
+   *
+   * @covers ::toUrl
+   *
+   * @dataProvider providerTestToUrl
+   */
+  public function testToUrl($entity_class, $link_template, $expected, $langcode = NULL) {
+    /** @var \Drupal\Core\Entity\EntityInterface $entity */
+    $entity = $this->getMockForAbstractClass($entity_class, array(array('id' => 'test_entity_id'), 'test_entity_type'));
+    $uri = $this->getTestToUrl($entity, $link_template, [], $langcode);
+
+    $this->assertSame($expected, $uri->getRouteName());
+    $this->assertSame($entity, $uri->getOption('entity'));
+
+    if ($langcode) {
+      $this->assertEquals($langcode, $uri->getOption('language')->getId());
+    }
+    else {
+      if ($entity instanceof ConfigEntityInterface) {
+        // Config entities do not provide a language with their URIs.
+        $this->assertEquals(NULL, $uri->getOption('language'));
+      }
+      else {
+        $this->assertEquals(LanguageInterface::LANGCODE_NOT_SPECIFIED, $uri->getOption('language')->getId());
+      }
+    }
+  }
 
   /**
-   * @covers ::urlInfo
+   * Tests for Entity::toUrl() exercising different language options.
+   *
+   * @covers ::toUrl
    */
-  public function testUrlInfoWithSpecificLanguageInOptions() {
-    /** @var $entity \Drupal\Core\Entity\EntityInterface */
+  public function testToUrlWithSpecificLanguageInOptions() {
+    /** @var \Drupal\Core\Entity\EntityInterface $entity */
     $entity = $this->getMockForAbstractClass('Drupal\Core\Entity\Entity', array(array('id' => 'test_entity_id'), 'test_entity_type'));
 
     // Ensure that a specified language overrides the current translation
     // language.
-    $uri = $this->getTestUrlInfo($entity, 'edit-form', [], 'en');
+    $uri = $this->getTestToUrl($entity, 'edit-form', [], 'en');
     $this->assertEquals('en', $uri->getOption('language')->getId());
 
-    $uri = $this->getTestUrlInfo($entity, 'edit-form', ['language' => new Language(['id' => 'fr'])], 'en');
+    $uri = $this->getTestToUrl($entity, 'edit-form', ['language' => new Language(['id' => 'fr'])], 'en');
     $this->assertEquals('fr', $uri->getOption('language')->getId());
   }
 
   /**
    * Provides test data for testUrlInfo().
    */
-  public function providerTestUrlInfo() {
+  public function providerTestToUrl() {
     return array(
       array('Drupal\Core\Entity\Entity', 'edit-form', 'entity.test_entity_type.edit_form', NULL),
       // Specify a langcode.
@@ -108,19 +143,20 @@ public function providerTestUrlInfo() {
   }
 
   /**
-   * Tests the urlInfo() method with an invalid link template.
+   * Tests the toUrl() method with an invalid link template.
    *
-   * @covers ::urlInfo
+   * @covers ::toUrl
    *
    * @expectedException \Drupal\Core\Entity\Exception\UndefinedLinkTemplateException
+   *
    * @expectedExceptionMessage No link template 'canonical' found for the 'test_entity_type' entity type
    *
-   * @dataProvider providerTestUrlInfoForInvalidLinkTemplate
+   * @dataProvider providerTestToUrlForInvalidLinkTemplate
    */
-  public function testUrlInfoForInvalidLinkTemplate($entity_class, $link_template) {
-    /** @var $entity \Drupal\Core\Entity\EntityInterface */
+  public function testToUrlForInvalidLinkTemplate($entity_class, $link_template) {
+    /** @var \Drupal\Core\Entity\EntityInterface $entity */
     $entity = $this->getMockForAbstractClass($entity_class, array(array('id' => 'test_entity_id'), 'test_entity_type'));
-    $uri = $this->getTestUrlInfo($entity, $link_template);
+    $uri = $this->getTestToUrl($entity, $link_template);
 
     $this->assertEmpty($uri);
   }
@@ -128,7 +164,7 @@ public function testUrlInfoForInvalidLinkTemplate($entity_class, $link_template)
   /**
    * Provides test data for testUrlInfoForInvalidLinkTemplate().
    */
-  public function providerTestUrlInfoForInvalidLinkTemplate() {
+  public function providerTestToUrlForInvalidLinkTemplate() {
     return array(
       array('Drupal\Core\Entity\Entity', 'canonical'),
       array('Drupal\Core\Entity\Entity', FALSE),
@@ -139,6 +175,9 @@ public function providerTestUrlInfoForInvalidLinkTemplate() {
   /**
    * Creates a \Drupal\Core\Url object based on the entity and link template.
    *
+   * Method urlInfo() is deprecated and replaced with toUrl().
+   * See also getTestToUrl().
+   *
    * @param \Drupal\Core\Entity\EntityInterface $entity
    *   The test entity.
    * @param string $link_template
@@ -184,17 +223,64 @@ protected function getTestUrlInfo(EntityInterface $entity, $link_template, array
   }
 
   /**
-   * Tests the urlInfo() method when an entity is still "new".
+   * Creates a \Drupal\Core\Url object based on the entity and link template.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $entity
+   *   The test entity.
+   * @param string $link_template
+   *   The link template.
+   * @param string $langcode
+   *   The langcode.
+   *
+   * @return \Drupal\Core\Url
+   *   The URL for this entity's link template.
+   */
+  protected function getTestToUrl(EntityInterface $entity, $link_template, array $options = [], $langcode = NULL) {
+    $entity_type = $this->getMock('Drupal\Core\Entity\EntityTypeInterface');
+    $entity_type->expects($this->any())
+      ->method('getLinkTemplates')
+      ->will($this->returnValue(array(
+        'edit-form' => 'test_entity_type.edit',
+      )));
+
+    if ($langcode) {
+      $entity->langcode = $langcode;
+    }
+
+    $this->entityManager
+      ->expects($this->any())
+      ->method('getDefinition')
+      ->with('test_entity_type')
+      ->will($this->returnValue($entity_type));
+
+    // If no link template is given, call without a value to test the default.
+    if ($link_template) {
+      $uri = $entity->toUrl($link_template, $options);
+    }
+    else {
+      if ($entity instanceof ConfigEntityInterface) {
+        $uri = $entity->toUrl('edit-form', $options);
+      }
+      else {
+        $uri = $entity->toUrl('canonical', $options);
+      }
+    }
+
+    return $uri;
+  }
+
+  /**
+   * Tests the toUrl() method when an entity is still "new".
    *
    * @see \Drupal\Core\Entity\EntityInterface::isNew()
    *
-   * @covers ::urlInfo
+   * @covers ::toUrl
    *
    * @expectedException \Drupal\Core\Entity\EntityMalformedException
    */
-  public function testUrlInfoForNewEntity() {
+  public function testToUrlForNewEntity() {
     $entity = $this->getMockForAbstractClass('Drupal\Core\Entity\Entity', array(array(), 'test_entity_type'));
-    $entity->urlInfo();
+    $entity->toUrl();
   }
 
   /**
@@ -236,7 +322,7 @@ public function testUrl() {
         if ($route_name === 'entity.test_entity_type.canonical' && $route_parameters === array('test_entity_type' => 'test_entity_id') && array_keys($options) === ['absolute', 'entity_type', 'entity', 'language'] && $options['language'] == $language) {
           return 'http://drupal/entity/test_entity_type/test_entity_id';
         }
-    });
+      });
 
     $this->assertSame('/entity/test_entity_type/test_entity_id', $valid_entity->url());
     $this->assertSame('http://drupal/entity/test_entity_type/test_entity_id', $valid_entity->url('canonical', array('absolute' => TRUE)));
