diff --git a/core/modules/config_translation/src/ConfigEntityMapper.php b/core/modules/config_translation/src/ConfigEntityMapper.php
index 08ce8a6..d7c5592 100644
--- a/core/modules/config_translation/src/ConfigEntityMapper.php
+++ b/core/modules/config_translation/src/ConfigEntityMapper.php
@@ -13,12 +13,12 @@
 use Drupal\Core\Entity\EntityManagerInterface;
 use Drupal\Core\Language\LanguageManagerInterface;
 use Drupal\Core\Routing\RouteMatch;
+use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\Core\Routing\RouteProviderInterface;
 use Drupal\Core\StringTranslation\TranslationInterface;
 use Drupal\Core\Url;
 use Drupal\locale\LocaleConfigManager;
 use Symfony\Component\DependencyInjection\ContainerInterface;
-use Symfony\Component\HttpFoundation\Request;
 use Symfony\Component\Routing\Route;
 
 /**
@@ -110,9 +110,9 @@ public static function create(ContainerInterface $container, array $configuratio
   /**
    * {@inheritdoc}
    */
-  public function populateFromRequest(Request $request) {
-    parent::populateFromRequest($request);
-    $entity = $request->attributes->get($this->entityType);
+  public function populateFromRouteMatch(RouteMatchInterface $route_match) {
+    parent::populateFromRouteMatch($route_match);
+    $entity = $route_match->getParameter($this->entityType);
     $this->setEntity($entity);
   }
 
diff --git a/core/modules/config_translation/src/ConfigMapperInterface.php b/core/modules/config_translation/src/ConfigMapperInterface.php
index ac3d531..8926d30 100644
--- a/core/modules/config_translation/src/ConfigMapperInterface.php
+++ b/core/modules/config_translation/src/ConfigMapperInterface.php
@@ -8,6 +8,7 @@
 namespace Drupal\config_translation;
 
 use Drupal\Core\Language\LanguageInterface;
+use Drupal\Core\Routing\RouteMatchInterface;
 use Symfony\Component\HttpFoundation\Request;
 use Symfony\Component\Routing\RouteCollection;
 
@@ -205,6 +206,16 @@ public function getConfigData();
   public function getLangcode();
 
   /**
+   * Sets the original language code.
+   *
+   * @param string $langcode
+   *   The langcode.
+   *
+   * @return $this
+   */
+  public function setLangcode($langcode);
+
+  /**
    * Returns language object for the configuration.
    *
    * If the language of the configuration files is not a configured language on
@@ -283,10 +294,10 @@ public function hasTranslation(LanguageInterface $language);
    *
    * @todo Replace $request with RouteMatch https://www.drupal.org/node/2295255.
    *
-   * @param \Symfony\Component\HttpFoundation\Request $request
-   *   Page request object.
+   * @param \Drupal\Core\Routing\RouteMatchInterface $route_match
+   *   The route match.
    */
-  public function populateFromRequest(Request $request);
+  public function populateFromRouteMatch(RouteMatchInterface $route_match);
 
   /**
    * Returns the name of the contextual link group to add contextual links to.
diff --git a/core/modules/config_translation/src/ConfigNamesMapper.php b/core/modules/config_translation/src/ConfigNamesMapper.php
index b681b33..7d9afaa 100644
--- a/core/modules/config_translation/src/ConfigNamesMapper.php
+++ b/core/modules/config_translation/src/ConfigNamesMapper.php
@@ -13,13 +13,13 @@
 use Drupal\Core\Language\LanguageInterface;
 use Drupal\Core\Language\LanguageManagerInterface;
 use Drupal\Core\Plugin\PluginBase;
+use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\Core\Routing\RouteProviderInterface;
 use Drupal\Core\StringTranslation\TranslationInterface;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
 use Drupal\Core\Url;
 use Drupal\locale\LocaleConfigManager;
 use Symfony\Component\DependencyInjection\ContainerInterface;
-use Symfony\Component\HttpFoundation\Request;
 use Symfony\Component\Routing\Route;
 use Symfony\Component\Routing\RouteCollection;
 
@@ -371,13 +371,8 @@ public function getWeight() {
   /**
    * {@inheritdoc}
    */
-  public function populateFromRequest(Request $request) {
-    if ($request->attributes->has('langcode')) {
-      $this->langcode = $request->attributes->get('langcode');
-    }
-    else {
-      $this->langcode = NULL;
-    }
+  public function populateFromRouteMatch(RouteMatchInterface $route_match) {
+    $this->langcode = $route_match->getParameter('langcode');
   }
 
   /**
@@ -410,6 +405,15 @@ public function getLangcode() {
   /**
    * {@inheritdoc}
    */
+  public function setLangcode($langcode) {
+    $this->langcode = $langcode;
+    return $this;
+  }
+
+
+  /**
+   * {@inheritdoc}
+   */
   public function getLanguageWithFallback() {
     $langcode = $this->getLangcode();
     $language = $this->languageManager->getLanguage($langcode);
diff --git a/core/modules/config_translation/src/Controller/ConfigTranslationController.php b/core/modules/config_translation/src/Controller/ConfigTranslationController.php
index 72fe9cc..e9c396d 100644
--- a/core/modules/config_translation/src/Controller/ConfigTranslationController.php
+++ b/core/modules/config_translation/src/Controller/ConfigTranslationController.php
@@ -13,6 +13,7 @@
 use Drupal\Core\Language\Language;
 use Drupal\Core\Language\LanguageManagerInterface;
 use Drupal\Core\PathProcessor\InboundPathProcessorInterface;
+use Drupal\Core\Routing\RouteMatch;
 use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\Core\Url;
@@ -122,7 +123,7 @@ public static function create(ContainerInterface $container) {
   public function itemPage(Request $request, RouteMatchInterface $route_match, $plugin_id) {
     /** @var \Drupal\config_translation\ConfigMapperInterface $mapper */
     $mapper = $this->configMapperManager->createInstance($plugin_id);
-    $mapper->populateFromRequest($request);
+    $mapper->populateFromRouteMatch($route_match);
 
     $page = array();
     $page['#title'] = $this->t('Translations for %label', array('%label' => $mapper->getTitle()));
@@ -143,7 +144,7 @@ public function itemPage(Request $request, RouteMatchInterface $route_match, $pl
     }
 
     // We create a fake request object to pass into
-    // ConfigMapperInterface::populateFromRequest() for the different languages.
+    // ConfigMapperInterface::populateFromRouteMatch() for the different languages.
     // Creating a separate request for each language and route is neither easily
     // possible nor performant.
     $fake_request = $request->duplicate();
@@ -158,8 +159,9 @@ public function itemPage(Request $request, RouteMatchInterface $route_match, $pl
       // This is needed because
       // ConfigMapperInterface::getAddRouteParameters(), for example,
       // needs to return the correct language code for each table row.
-      $fake_request->attributes->set('langcode', $langcode);
-      $mapper->populateFromRequest($fake_request);
+      $fake_route_match = RouteMatch::createFromRequest($fake_request);
+      $mapper->populateFromRouteMatch($fake_route_match);
+      $mapper->setLangcode($langcode);
 
       // Prepare the language name and the operations depending on whether this
       // is the original language or not.
diff --git a/core/modules/config_translation/src/Form/ConfigTranslationDeleteForm.php b/core/modules/config_translation/src/Form/ConfigTranslationDeleteForm.php
index f603740..eb32499 100644
--- a/core/modules/config_translation/src/Form/ConfigTranslationDeleteForm.php
+++ b/core/modules/config_translation/src/Form/ConfigTranslationDeleteForm.php
@@ -12,6 +12,7 @@
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Form\ConfirmFormBase;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\Core\Url;
 use Drupal\language\ConfigurableLanguageManagerInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -116,10 +117,10 @@ public function getFormID() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, FormStateInterface $form_state, Request $request = NULL, $plugin_id = NULL, $langcode = NULL) {
+  public function buildForm(array $form, FormStateInterface $form_state, RouteMatchInterface $route_match = NULL, $plugin_id = NULL, $langcode = NULL) {
     /** @var \Drupal\config_translation\ConfigMapperInterface $mapper */
     $mapper = $this->configMapperManager->createInstance($plugin_id);
-    $mapper->populateFromRequest($request);
+    $mapper->populateFromRouteMatch($route_match);
 
     $language = $this->languageManager->getLanguage($langcode);
     if (!$language) {
diff --git a/core/modules/config_translation/src/Form/ConfigTranslationFormBase.php b/core/modules/config_translation/src/Form/ConfigTranslationFormBase.php
index 2831fd9..372635a 100644
--- a/core/modules/config_translation/src/Form/ConfigTranslationFormBase.php
+++ b/core/modules/config_translation/src/Form/ConfigTranslationFormBase.php
@@ -9,6 +9,7 @@
 
 use Drupal\config_translation\ConfigMapperManagerInterface;
 use Drupal\Core\Config\TypedConfigManagerInterface;
+use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\Core\TypedData\TypedDataInterface;
 use Drupal\Core\TypedData\TraversableTypedDataInterface;
 use Drupal\Core\Form\BaseFormIdInterface;
@@ -132,10 +133,10 @@ public function getBaseFormId() {
    *   Throws an exception if the language code provided as a query parameter in
    *   the request does not match an active language.
    */
-  public function buildForm(array $form, FormStateInterface $form_state, Request $request = NULL, $plugin_id = NULL, $langcode = NULL) {
+  public function buildForm(array $form, FormStateInterface $form_state, RouteMatchInterface $route_match = NULL, $plugin_id = NULL, $langcode = NULL) {
     /** @var \Drupal\config_translation\ConfigMapperInterface $mapper */
     $mapper = $this->configMapperManager->createInstance($plugin_id);
-    $mapper->populateFromRequest($request);
+    $mapper->populateFromRouteMatch($route_match);
 
     $language = $this->languageManager->getLanguage($langcode);
     if (!$language) {
diff --git a/core/modules/config_translation/tests/src/Unit/ConfigNamesMapperTest.php b/core/modules/config_translation/tests/src/Unit/ConfigNamesMapperTest.php
index 0b3ead9..a080067 100644
--- a/core/modules/config_translation/tests/src/Unit/ConfigNamesMapperTest.php
+++ b/core/modules/config_translation/tests/src/Unit/ConfigNamesMapperTest.php
@@ -11,6 +11,7 @@
 use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\DependencyInjection\ContainerBuilder;
 use Drupal\Core\Language\Language;
+use Drupal\Core\Routing\RouteMatch;
 use Drupal\Core\Url;
 use Drupal\Tests\UnitTestCase;
 use Symfony\Component\Routing\Route;
@@ -239,9 +240,8 @@ public function testGetAddRouteName() {
    * Tests ConfigNamesMapper::getAddRouteParameters().
    */
   public function testGetAddRouteParameters() {
-    $request = Request::create('');
-    $request->attributes->set('langcode', 'xx');
-    $this->configNamesMapper->populateFromRequest($request);
+    $route_match = new RouteMatch('example', new Route('/test/{langcode}'), ['langcode' => 'xx']);
+    $this->configNamesMapper->populateFromRouteMatch($route_match);
 
     $expected = array('langcode' => 'xx');
     $result = $this->configNamesMapper->getAddRouteParameters();
@@ -278,9 +278,8 @@ public function testGetEditRouteName() {
    * Tests ConfigNamesMapper::getEditRouteParameters().
    */
   public function testGetEditRouteParameters() {
-    $request = Request::create('');
-    $request->attributes->set('langcode', 'xx');
-    $this->configNamesMapper->populateFromRequest($request);
+    $route_match = new RouteMatch('example', new Route('/test/{langcode}'), ['langcode' => 'xx']);
+    $this->configNamesMapper->populateFromRouteMatch($route_match);
 
     $expected = array('langcode' => 'xx');
     $result = $this->configNamesMapper->getEditRouteParameters();
@@ -317,9 +316,8 @@ public function testGetDeleteRouteName() {
    * Tests ConfigNamesMapper::getDeleteRouteParameters().
    */
   public function testGetDeleteRouteParameters() {
-    $request = Request::create('');
-    $request->attributes->set('langcode', 'xx');
-    $this->configNamesMapper->populateFromRequest($request);
+    $route_match = new RouteMatch('example', new Route('/test/{langcode}'), ['langcode' => 'xx']);
+    $this->configNamesMapper->populateFromRouteMatch($route_match);
 
     $expected = array('langcode' => 'xx');    $result = $this->configNamesMapper->getDeleteRouteParameters();
     $this->assertSame($expected, $result);
@@ -370,25 +368,25 @@ public function testGetWeight() {
   }
 
   /**
-   * Tests ConfigNamesMapper::populateFromRequest().
+   * Tests ConfigNamesMapper::populateFromRouteMatch().
    */
-  public function testPopulateFromRequest() {
+  public function testPopulateFromRouteMatch() {
     // Make sure the language code is not set initially.
     $this->assertSame(NULL, $this->configNamesMapper->getInternalLangcode());
 
     // Test that an empty request does not set the language code.
-    $request = Request::create('');
-    $this->configNamesMapper->populateFromRequest($request);
+    $route_match = new RouteMatch('example', new Route('/test/{langcode}'));
+    $this->configNamesMapper->populateFromRouteMatch($route_match);
     $this->assertSame(NULL, $this->configNamesMapper->getInternalLangcode());
 
     // Test that a request with a 'langcode' attribute sets the language code.
-    $request->attributes->set('langcode', 'xx');
-    $this->configNamesMapper->populateFromRequest($request);
+    $route_match = new RouteMatch('example', new Route('/test/{langcode}'), ['langcode' => 'xx']);
+    $this->configNamesMapper->populateFromRouteMatch($route_match);
     $this->assertSame('xx', $this->configNamesMapper->getInternalLangcode());
 
     // Test that the language code gets unset with the wrong request.
-    $request->attributes->remove('langcode');
-    $this->configNamesMapper->populateFromRequest($request);
+    $route_match = new RouteMatch('example', new Route('/test/{langcode}'));
+    $this->configNamesMapper->populateFromRouteMatch($route_match);
     $this->assertSame(NULL, $this->configNamesMapper->getInternalLangcode());
   }
 
