diff --git a/core/modules/config_translation/src/Access/ConfigTranslationFormAccess.php b/core/modules/config_translation/src/Access/ConfigTranslationFormAccess.php
index 4e041ce..cc48061 100644
--- a/core/modules/config_translation/src/Access/ConfigTranslationFormAccess.php
+++ b/core/modules/config_translation/src/Access/ConfigTranslationFormAccess.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\config_translation\Access;
 
+use Drupal\config_translation\Exception\ConfigMapperLanguageException;
 use Drupal\Core\Access\AccessResult;
 use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\Core\Session\AccountInterface;
@@ -19,18 +20,29 @@ public function access(RouteMatchInterface $route_match, AccountInterface $accou
     // checks in addition to the checks performed for the translation overview.
     $base_access = parent::access($route_match, $account);
     if ($base_access->isAllowed()) {
-      $target_language = $this->languageManager->getLanguage($langcode);
-
-      // Make sure that the target language is not locked, and that the target
-      // language is not the original submission language. Although technically
-      // configuration can be overlaid with translations in the same language,
-      // that is logically not a good idea.
-      $access =
-        !empty($target_language) &&
-        !$target_language->isLocked() &&
-        (empty($this->sourceLanguage) || ($target_language->getId() != $this->sourceLanguage->getId()));
-
-      return $base_access->andIf(AccessResult::allowedIf($access));
+      try {
+        // We do not use the result value, but we need to check that the mapper
+        // only has a single language code.
+        $this->mapper->getLangcode();
+
+        $target_language = $this->languageManager->getLanguage($langcode);
+
+        // Make sure that the target language is not locked, and that the target
+        // language is not the original submission language. Although
+        // technically configuration can be overlaid with translations in the
+        // same language, that is logically not a good idea.
+        $access =
+          !empty($target_language) &&
+          !$target_language->isLocked() &&
+          (empty($this->sourceLanguage) || ($target_language->getId() != $this->sourceLanguage->getId()));
+
+        return $base_access->andIf(AccessResult::allowedIf($access));
+      }
+      catch (ConfigMapperLanguageException $exception) {
+        // In contrast to ConfigTranslationOverviewAccess this does not grant
+        // access to a mapper if the languages do not match.
+        return AccessResult::forbidden()->inheritCacheability($base_access);
+      }
     }
     return $base_access;
   }
diff --git a/core/modules/config_translation/src/Access/ConfigTranslationOverviewAccess.php b/core/modules/config_translation/src/Access/ConfigTranslationOverviewAccess.php
index 91ccf49..1fa4fbc 100644
--- a/core/modules/config_translation/src/Access/ConfigTranslationOverviewAccess.php
+++ b/core/modules/config_translation/src/Access/ConfigTranslationOverviewAccess.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\config_translation\Access;
 
+use Drupal\config_translation\Exception\ConfigMapperLanguageException;
 use Drupal\Core\Language\LanguageManagerInterface;
 use Drupal\config_translation\ConfigMapperManagerInterface;
 use Drupal\Core\Access\AccessResult;
@@ -29,6 +30,13 @@ class ConfigTranslationOverviewAccess implements AccessInterface {
   protected $languageManager;
 
   /**
+   * The configuration mapper to check access for.
+   *
+   * @var \Drupal\config_translation\ConfigMapperInterface
+   */
+  protected $mapper;
+
+  /**
    * The source language.
    *
    * @var \Drupal\Core\Language\LanguageInterface
@@ -62,10 +70,19 @@ public function __construct(ConfigMapperManagerInterface $config_mapper_manager,
   public function access(RouteMatchInterface $route_match, AccountInterface $account) {
     $route = $route_match->getRouteObject();
 
-    /** @var \Drupal\config_translation\ConfigMapperInterface $mapper */
-    $mapper = $this->configMapperManager->createInstance($route->getDefault('plugin_id'));
-    $mapper->populateFromRouteMatch($route_match);
-    $this->sourceLanguage = $this->languageManager->getLanguage($mapper->getLangcode());
+    $this->mapper = $this->configMapperManager->createInstance($route->getDefault('plugin_id'));
+    $this->mapper->populateFromRouteMatch($route_match);
+
+    try {
+      $langcode = $this->mapper->getLangcode();
+    }
+    catch (ConfigMapperLanguageException $exception) {
+      // ConfigTranslationController shows a helpful message if the language
+      // codes do not match, so do not let that prevent granting access.
+      $langcode = 'en';
+    }
+
+    $this->sourceLanguage = $this->languageManager->getLanguage($langcode);
 
     // Allow access to the translation overview if the proper permission is
     // granted, the configuration has translatable pieces, and the source
@@ -73,8 +90,8 @@ public function access(RouteMatchInterface $route_match, AccountInterface $accou
     $source_language_access = is_null($this->sourceLanguage) || !$this->sourceLanguage->isLocked();
     $access =
       $account->hasPermission('translate configuration') &&
-      $mapper->hasSchema() &&
-      $mapper->hasTranslatable() &&
+      $this->mapper->hasSchema() &&
+      $this->mapper->hasTranslatable() &&
       $source_language_access;
 
     return AccessResult::allowedIf($access)->cachePerPermissions();
diff --git a/core/modules/config_translation/src/ConfigMapperInterface.php b/core/modules/config_translation/src/ConfigMapperInterface.php
index be26d4e..57c1ccd 100644
--- a/core/modules/config_translation/src/ConfigMapperInterface.php
+++ b/core/modules/config_translation/src/ConfigMapperInterface.php
@@ -203,6 +203,17 @@ public function getConfigData();
   public function getLangcode();
 
   /**
+   * Returns the language code of a configuration object given its name.
+   *
+   * @param string $config_name
+   *   The name of the configuration object.
+   *
+   * @return string
+   *   The language code of the configuration object.
+   */
+  public function getLangcodeFromConfig($config_name);
+
+  /**
    * Sets the original language code.
    *
    * @param string $langcode
diff --git a/core/modules/config_translation/src/ConfigNamesMapper.php b/core/modules/config_translation/src/ConfigNamesMapper.php
index 5b6028a..bb82fe5 100644
--- a/core/modules/config_translation/src/ConfigNamesMapper.php
+++ b/core/modules/config_translation/src/ConfigNamesMapper.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\config_translation;
 
+use Drupal\config_translation\Exception\ConfigMapperLanguageException;
 use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\Config\TypedConfigManagerInterface;
 use Drupal\Core\Language\LanguageInterface;
@@ -380,17 +381,10 @@ public function getTypeLabel() {
    * {@inheritdoc}
    */
   public function getLangcode() {
-    $config_factory = $this->configFactory;
-    $langcodes = array_map(function($name) use ($config_factory) {
-      // Default to English if no language code was provided in the file.
-      // Although it is a best practice to include a language code, if the
-      // developer did not think about a multilingual use-case, we fall back
-      // on assuming the file is English.
-      return $config_factory->get($name)->get('langcode') ?: 'en';
-    }, $this->getConfigNames());
+    $langcodes = array_map([$this, 'getLangcodeFromConfig'], $this->getConfigNames());
 
     if (count(array_unique($langcodes)) > 1) {
-      throw new \RuntimeException('A config mapper can only contain configuration for a single language.');
+      throw new ConfigMapperLanguageException('A config mapper can only contain configuration for a single language.');
     }
 
     return reset($langcodes);
@@ -399,6 +393,17 @@ public function getLangcode() {
   /**
    * {@inheritdoc}
    */
+  public function getLangcodeFromConfig($config_name) {
+    // Default to English if no language code was provided in the file.
+    // Although it is a best practice to include a language code, if the
+    // developer did not think about a multilingual use case, we fall back
+    // on assuming the file is English.
+    return $this->configFactory->get($config_name)->get('langcode') ?: 'en';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function setLangcode($langcode) {
     $this->langcode = $langcode;
     return $this;
diff --git a/core/modules/config_translation/src/Controller/ConfigTranslationController.php b/core/modules/config_translation/src/Controller/ConfigTranslationController.php
index 376def0..927a1e2 100644
--- a/core/modules/config_translation/src/Controller/ConfigTranslationController.php
+++ b/core/modules/config_translation/src/Controller/ConfigTranslationController.php
@@ -3,11 +3,14 @@
 namespace Drupal\config_translation\Controller;
 
 use Drupal\config_translation\ConfigMapperManagerInterface;
+use Drupal\config_translation\Exception\ConfigMapperLanguageException;
 use Drupal\Core\Access\AccessManagerInterface;
 use Drupal\Core\Controller\ControllerBase;
 use Drupal\Core\Language\Language;
+use Drupal\Core\Language\LanguageInterface;
 use Drupal\Core\Language\LanguageManagerInterface;
 use Drupal\Core\PathProcessor\InboundPathProcessorInterface;
+use Drupal\Core\Render\RendererInterface;
 use Drupal\Core\Routing\RouteMatch;
 use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\Core\Session\AccountInterface;
@@ -64,6 +67,13 @@ class ConfigTranslationController extends ControllerBase {
   protected $languageManager;
 
   /**
+   * The renderer.
+   *
+   * @var \Drupal\Core\Render\RendererInterface
+   */
+  protected $renderer;
+
+  /**
    * Constructs a ConfigTranslationController.
    *
    * @param \Drupal\config_translation\ConfigMapperManagerInterface $config_mapper_manager
@@ -78,14 +88,17 @@ class ConfigTranslationController extends ControllerBase {
    *   The current user.
    * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
    *   The language manager.
+   * @param \Drupal\Core\Render\RendererInterface $renderer
+   *   The renderer.
    */
-  public function __construct(ConfigMapperManagerInterface $config_mapper_manager, AccessManagerInterface $access_manager, RequestMatcherInterface $router, InboundPathProcessorInterface $path_processor, AccountInterface $account, LanguageManagerInterface $language_manager) {
+  public function __construct(ConfigMapperManagerInterface $config_mapper_manager, AccessManagerInterface $access_manager, RequestMatcherInterface $router, InboundPathProcessorInterface $path_processor, AccountInterface $account, LanguageManagerInterface $language_manager, RendererInterface $renderer) {
     $this->configMapperManager = $config_mapper_manager;
     $this->accessManager = $access_manager;
     $this->router = $router;
     $this->pathProcessor = $path_processor;
     $this->account = $account;
     $this->languageManager = $language_manager;
+    $this->renderer = $renderer;
   }
 
   /**
@@ -98,7 +111,8 @@ public static function create(ContainerInterface $container) {
       $container->get('router'),
       $container->get('path_processor_manager'),
       $container->get('current_user'),
-      $container->get('language_manager')
+      $container->get('language_manager'),
+      $container->get('renderer')
     );
   }
 
@@ -127,7 +141,33 @@ public function itemPage(Request $request, RouteMatchInterface $route_match, $pl
     if (count($languages) == 1) {
       drupal_set_message($this->t('In order to translate configuration, the website must have at least two <a href=":url">languages</a>.', array(':url' => $this->url('entity.configurable_language.collection'))), 'warning');
     }
-    $original_langcode = $mapper->getLangcode();
+
+    try {
+      $original_langcode = $mapper->getLangcode();
+      $operations_access = TRUE;
+    }
+    catch (ConfigMapperLanguageException $exception) {
+      $items = [];
+      foreach ($mapper->getConfigNames() as $config_name) {
+        $langcode = $mapper->getLangcodeFromConfig($config_name);
+        $items[] = $this->t('@name: @langcode', [
+          '@name' => $config_name,
+          '@langcode'  => $langcode,
+        ]);
+      }
+      $message = [
+        'message' => ['#markup' => $this->t('The configuration objects have different language codes so they cannot be translated:')],
+        'items' => [
+          '#theme' => 'item_list',
+          '#items' => $items,
+        ],
+      ];
+      drupal_set_message($this->renderer->renderPlain($message), 'warning');
+
+      $original_langcode = LanguageInterface::LANGCODE_NOT_SPECIFIED;
+      $operations_access = FALSE;
+    }
+
     if (!isset($languages[$original_langcode])) {
       // If the language is not configured on the site, create a dummy language
       // object for this listing only to ensure the user gets useful info.
@@ -205,6 +245,9 @@ public function itemPage(Request $request, RouteMatchInterface $route_match, $pl
       $page['languages'][$langcode]['operations'] = array(
         '#type' => 'operations',
         '#links' => $operations,
+        // Even if the mapper contains multiple language codes, the source
+        // configuration can still be edited.
+        '#access' => ($langcode == $original_langcode) || $operations_access,
       );
     }
     return $page;
diff --git a/core/modules/config_translation/src/Exception/ConfigMapperLanguageException.php b/core/modules/config_translation/src/Exception/ConfigMapperLanguageException.php
new file mode 100644
index 0000000..db4d202
--- /dev/null
+++ b/core/modules/config_translation/src/Exception/ConfigMapperLanguageException.php
@@ -0,0 +1,9 @@
+<?php
+
+namespace Drupal\config_translation\Exception;
+
+/**
+ * Provides an exception for configuration mappers with multiple languages.
+ */
+class ConfigMapperLanguageException extends \RuntimeException {
+}
diff --git a/core/modules/config_translation/src/Form/ConfigTranslationFormBase.php b/core/modules/config_translation/src/Form/ConfigTranslationFormBase.php
index 68d58ab..5660663 100644
--- a/core/modules/config_translation/src/Form/ConfigTranslationFormBase.php
+++ b/core/modules/config_translation/src/Form/ConfigTranslationFormBase.php
@@ -4,6 +4,7 @@
 
 use Drupal\config_translation\ConfigMapperManagerInterface;
 use Drupal\Core\Config\TypedConfigManagerInterface;
+use Drupal\Core\Render\RendererInterface;
 use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\Core\TypedData\TypedDataInterface;
 use Drupal\Core\Form\BaseFormIdInterface;
@@ -138,7 +139,12 @@ public function buildForm(array $form, FormStateInterface $form_state, RouteMatc
 
     $this->mapper = $mapper;
     $this->language = $language;
-    $this->sourceLanguage = $this->languageManager->getLanguage($this->mapper->getLangcode());
+
+    // ConfigTranslationFormAccess will not grant access if this raises an
+    // exception, so we can call this without a try-catch block here.
+    $langcode = $this->mapper->getLangcode();
+
+    $this->sourceLanguage = $this->languageManager->getLanguage($langcode);
 
     // Get base language configuration to display in the form before setting the
     // language to use for the form. This avoids repetitively settings and
diff --git a/core/modules/node/src/Tests/NodeTypeTranslationTest.php b/core/modules/node/src/Tests/NodeTypeTranslationTest.php
index f86ccc4..1c3a768 100644
--- a/core/modules/node/src/Tests/NodeTypeTranslationTest.php
+++ b/core/modules/node/src/Tests/NodeTypeTranslationTest.php
@@ -23,7 +23,9 @@ class NodeTypeTranslationTest extends WebTestBase {
    * @var array
    */
   public static $modules = array(
+    'block',
     'config_translation',
+    'field_ui',
     'node',
   );
 
@@ -53,6 +55,8 @@ protected function setUp() {
 
     $admin_permissions = array(
       'administer content types',
+      'administer node fields',
+      'administer languages',
       'administer site configuration',
       'administer themes',
       'translate configuration',
@@ -144,6 +148,29 @@ public function testNodeTypeTitleLabelTranslation() {
     $this->assertText('Edited title');
     $this->drupalGet("$langcode/node/add/$type");
     $this->assertText('Translated title');
+
+    // Add an e-mail field.
+    $this->drupalPostForm("admin/structure/types/manage/$type/fields/add-field", array('new_storage_type' => 'email', 'label' => 'Email', 'field_name' => 'email'), 'Save and continue');
+    $this->drupalPostForm(NULL, array(), 'Save field settings');
+    $this->drupalPostForm(NULL, array(), 'Save settings');
+
+    $type = Unicode::strtolower($this->randomMachineName(16));
+    $name = $this->randomString();
+    $this->drupalCreateContentType(array('type' => $type, 'name' => $name));
+
+    // Set tabs.
+    $this->drupalPlaceBlock('local_tasks_block', array('primary' => TRUE));
+
+    // Change default language.
+    $this->drupalPostForm('admin/config/regional/language', array('site_default_language' => 'es'), 'Save configuration');
+
+    // Try re-using the email field.
+    $this->drupalGet("es/admin/structure/types/manage/$type/fields/add-field");
+    $this->drupalPostForm(NULL, array('existing_storage_name' => 'field_email', 'existing_storage_label' => 'Email'), 'Save and continue');
+    $this->assertResponse(200);
+    $this->drupalGet("es/admin/structure/types/manage/$type/fields/node.$type.field_email/translate");
+    $this->assertResponse(200);
+    $this->assertText("The configuration objects have different language codes so they cannot be translated");
   }
 
 }
