diff --git a/core/lib/Drupal/Core/Entity/ContentEntityBase.php b/core/lib/Drupal/Core/Entity/ContentEntityBase.php
index 9d502d2..0bcd35f 100644
--- a/core/lib/Drupal/Core/Entity/ContentEntityBase.php
+++ b/core/lib/Drupal/Core/Entity/ContentEntityBase.php
@@ -73,13 +73,6 @@
   protected $fieldDefinitions;
 
   /**
-   * Local cache for URI placeholder substitution values.
-   *
-   * @var array
-   */
-  protected $uriPlaceholderReplacements;
-
-  /**
    * Local cache for the available language objects.
    *
    * @var array
diff --git a/core/lib/Drupal/Core/Entity/Entity.php b/core/lib/Drupal/Core/Entity/Entity.php
index 2e4a7ea..2f9f996 100644
--- a/core/lib/Drupal/Core/Entity/Entity.php
+++ b/core/lib/Drupal/Core/Entity/Entity.php
@@ -38,11 +38,18 @@
   protected $enforceIsNew;
 
   /**
-   * The route provider service.
+   * Local cache for URI route placeholders.
    *
-   * @var \Drupal\Core\Routing\RouteProviderInterface
+   * @var array
    */
-  protected $routeProvider;
+  protected $uriRouteParameters;
+
+  /**
+   * The URL generator.
+   *
+   * @var \Drupal\Core\Routing\UrlGeneratorInterface
+   */
+  protected $urlGenerator;
 
   /**
    * Constructs an Entity object.
@@ -153,30 +160,28 @@ public function uri($rel = 'canonical') {
     // The links array might contain URI templates set in annotations.
     $link_templates = $entity_info->getLinkTemplates();
 
-    $template = NULL;
     if (isset($link_templates[$rel])) {
       try {
-        $template = $this->routeProvider()->getRouteByName($link_templates[$rel])->getPath();
+        // If there is a template for the given relationship type, generate the path.
+        $uri['path'] = $this->urlGenerator()->generateFromRoute($link_templates[$rel], $this->uriRouteParameters());
+
+        // @todo Remove this once http://drupal.org/node/1888424 is in and we can
+        //   move the BC handling of / vs. no-/ to the generator.
+        $uri['path'] = trim($uri['path'], '/');
+
+        // Pass the entity data to url() so that alter functions do not need to
+        // look up this entity again.
+        $uri['options']['entity_type'] = $this->entityType;
+        $uri['options']['entity'] = $this;
+        return $uri;
       }
       catch (RouteNotFoundException $e) {
         // Fall back to a non-template-based URI.
       }
-    }
-    if ($template) {
-      // If there is a template for the given relationship type, do the
-      // placeholder replacement and use that as the path.
-      $replacements = $this->uriPlaceholderReplacements();
-      $uri['path'] = str_replace(array_keys($replacements), array_values($replacements), $template);
-
-      // @todo Remove this once http://drupal.org/node/1888424 is in and we can
-      //   move the BC handling of / vs. no-/ to the generator.
-      $uri['path'] = trim($uri['path'], '/');
-
-      // Pass the entity data to url() so that alter functions do not need to
-      // look up this entity again.
-      $uri['options']['entity_type'] = $this->entityType;
-      $uri['options']['entity'] = $this;
-      return $uri;
+      // @todo Remove this check once everything works.
+      catch (\Symfony\Component\Routing\Exception\MissingMandatoryParametersException $e) {
+        throw new \Exception($this->entityType() . ': ' . $e->getMessage());
+      }
     }
 
     $bundle = $this->bundle();
@@ -204,7 +209,7 @@ public function uri($rel = 'canonical') {
       );
     }
     else {
-      return array();
+      return NULL;
     }
 
     // Pass the entity data to url() so that alter functions do not need to
@@ -223,17 +228,14 @@ public function uri($rel = 'canonical') {
    * @return array
    *   An array of URI placeholders.
    */
-  protected function uriPlaceholderReplacements() {
-    if (empty($this->uriPlaceholderReplacements)) {
-      $this->uriPlaceholderReplacements = array(
-        '{entityType}' => $this->entityType(),
-        '{bundle}' => $this->bundle(),
-        '{id}' => $this->id(),
-        '{uuid}' => $this->uuid(),
-        '{' . $this->entityType() . '}' => $this->id(),
-      );
+  protected function uriRouteParameters() {
+    if (empty($this->uriRouteParameters)) {
+      $this->uriRouteParameters[$this->entityType()] = $this->id();
+      if ($this->entityType() != $this->bundle()) {
+        $this->uriRouteParameters[$this->entityInfo()->getBundleEntityType()] = $this->bundle();
+      }
     }
-    return $this->uriPlaceholderReplacements;
+    return $this->uriRouteParameters;
   }
 
   /**
@@ -387,16 +389,16 @@ public function changed() {
   }
 
   /**
-   * Wraps the route provider service.
+   * Wraps the URL generator.
    *
-   * @return \Drupal\Core\Routing\RouteProviderInterface
-   *   The route provider.
+   * @return \Drupal\Core\Routing\UrlGeneratorInterface
+   *   The URL generator.
    */
-  protected function routeProvider() {
-    if (!$this->routeProvider) {
-      $this->routeProvider = \Drupal::service('router.route_provider');
+  protected function urlGenerator() {
+    if (!$this->urlGenerator) {
+      $this->urlGenerator = \Drupal::urlGenerator();
     }
-    return $this->routeProvider;
+    return $this->urlGenerator;
   }
 
 }
diff --git a/core/lib/Drupal/Core/Entity/EntityTypeInterface.php b/core/lib/Drupal/Core/Entity/EntityTypeInterface.php
index 4cb05aa..5771821 100644
--- a/core/lib/Drupal/Core/Entity/EntityTypeInterface.php
+++ b/core/lib/Drupal/Core/Entity/EntityTypeInterface.php
@@ -315,17 +315,14 @@ public function isFieldable();
    * HTML page must also define an "edit-form" relationship.
    *
    * By default, the following placeholders are supported:
-   * - entityType: The machine name of the entity type.
-   * - bundle: The bundle machine name of the entity.
-   * - id: The unique ID of the entity.
-   * - uuid: The UUID of the entity.
    * - [entityType]: The entity type itself will also be a valid token for the
    *   ID of the entity. For instance, a placeholder of {node} used on the Node
-   *   class would have the same value as {id}. This is generally preferred
-   *   over "id" for better self-documentation.
+   *   class.
+   * - [bundleEntityType]: The bundle machine name itself. For instance, a
+   *   placeholder of {node_type} used on the Node class.
    *
    * Specific entity types may also expand upon this list by overriding the
-   * Entity::uriPlaceholderReplacements() method.
+   * Entity::uriRouteParameters() method.
    *
    * @link http://www.iana.org/assignments/link-relations/link-relations.xml @endlink
    * @link http://tools.ietf.org/html/rfc6570 @endlink
