diff --git a/core/modules/language/src/ConfigurableLanguageManager.php b/core/modules/language/src/ConfigurableLanguageManager.php
index 238bd83..a6aceb3 100644
--- a/core/modules/language/src/ConfigurableLanguageManager.php
+++ b/core/modules/language/src/ConfigurableLanguageManager.php
@@ -90,11 +90,15 @@ class ConfigurableLanguageManager extends LanguageManager implements Configurabl
   protected $initialized = FALSE;
 
   /**
-   * Whether already in the process of language initialization.
+   * The language types currently being initialized.
    *
-   * @var bool
+   * @var bool[]
+   *   An array of which the keys are language type names, and values are
+   *   booleans indicating whether or not the language for that type is
+   *   currently being initialized. If a language type is missing, it is
+   *   currently not being initialized.
    */
-  protected $initializing = FALSE;
+  protected $initializing = [];
 
   /**
    * {@inheritdoc}
@@ -213,12 +217,15 @@ public function getCurrentLanguage($type = LanguageInterface::TYPE_INTERFACE) {
       $this->negotiatedLanguages[$type] = $this->getDefaultLanguage();
 
       if ($this->negotiator && $this->isMultilingual()) {
-        if (!$this->initializing) {
-          $this->initializing = TRUE;
+        if (empty($this->initializing[$type])) {
+          // Set a flag indicating that we're currently initializing the
+          // language-type to prevent recursive initialization.
+          $this->initializing[$type] = TRUE;
+
           $negotiation = $this->negotiator->initializeType($type);
           $this->negotiatedLanguages[$type] = reset($negotiation);
           $this->negotiatedMethods[$type] = key($negotiation);
-          $this->initializing = FALSE;
+          unset($this->initializing[$type]);
         }
         // If the current interface language needs to be retrieved during
         // initialization we return the system language. This way string
@@ -311,7 +318,10 @@ public function getLanguages($flags = LanguageInterface::STATE_CONFIGURABLE) {
         $data['name'] = $data['label'];
         $languages[$data['id']] = new Language($data);
       }
-      Language::sort($languages);
+      // The sort function calls methods on the languages. For mocked methods,
+      // this results in state changes, triggering an "Array was modified by the
+      // user comparison function" error. Suppress all errors because of this.
+      @Language::sort($languages);
 
       // Filter the full list of languages based on the value of $flags.
       $this->languages[$static_cache_id][$flags] = $this->filterLanguages($languages, $flags);
diff --git a/core/modules/language/tests/src/Unit/ConfigurableLanguageManagerTest.php b/core/modules/language/tests/src/Unit/ConfigurableLanguageManagerTest.php
new file mode 100644
index 0000000..6a93b7e
--- /dev/null
+++ b/core/modules/language/tests/src/Unit/ConfigurableLanguageManagerTest.php
@@ -0,0 +1,145 @@
+<?php
+
+namespace Drupal\Tests\language\Unit;
+
+use Drupal\Core\Config\Config;
+use Drupal\Core\Config\ConfigFactoryInterface;
+use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\Language\LanguageDefault;
+use Drupal\Core\Language\LanguageInterface;
+use Drupal\language\Config\LanguageConfigFactoryOverrideInterface;
+use Drupal\language\ConfigurableLanguageManager;
+use Drupal\language\LanguageNegotiatorInterface;
+use Drupal\Tests\UnitTestCase;
+use Symfony\Component\HttpFoundation\RequestStack;
+
+/**
+ * @coversDefaultClass \Drupal\language\ConfigurableLanguageManager
+ *
+ * @group language
+ */
+class ConfigurableLanguageManagerTest extends UnitTestCase {
+
+  /**
+   * The configuration factory.
+   *
+   * @var \Drupal\Core\Config\ConfigFactoryInterface|\Prophecy\Prophecy\ObjectProphecy
+   */
+  protected $configFactory;
+
+  /**
+   * The language configuration override.
+   *
+   * @var \Drupal\language\Config\LanguageConfigFactoryOverrideInterface|\Prophecy\Prophecy\ObjectProphecy
+   */
+  protected $configFactoryOverride;
+
+  /**
+   * The default language.
+   *
+   * @var \Drupal\Core\Language\LanguageDefault|\Prophecy\Prophecy\ObjectProphecy
+   */
+  protected $defaultLanguage;
+
+  /**
+   * The module handler.
+   *
+   * @var \Drupal\Core\Extension\ModuleHandlerInterface|\Prophecy\Prophecy\ObjectProphecy
+   */
+  protected $moduleHandler;
+
+  /**
+   * The system under test.
+   *
+   * @var \Drupal\language\ConfigurableLanguageManager
+   */
+  protected $languageManager;
+
+  /**
+   * The language negotiator.
+   *
+   * @var \Drupal\language\LanguageNegotiatorInterface|\Prophecy\Prophecy\ObjectProphecy
+   */
+  protected $negotiator;
+
+  /**
+   * The request object.
+   *
+   * @var \Symfony\Component\HttpFoundation\RequestStack|\Prophecy\Prophecy\ObjectProphecy
+   */
+  protected $requestStack;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setUp() {
+    parent::setUp();
+
+    $this->configFactory = $this->prophesize(ConfigFactoryInterface::class);
+
+    $this->configFactoryOverride = $this->prophesize(LanguageConfigFactoryOverrideInterface::class);
+
+    $this->defaultLanguage = $this->prophesize(LanguageDefault::class);
+
+    $this->moduleHandler = $this->prophesize(ModuleHandlerInterface::class);
+
+    $this->negotiator = $this->prophesize(LanguageNegotiatorInterface::class);
+
+    $this->requestStack = $this->prophesize(RequestStack::class);
+
+    $this->languageManager = new ConfigurableLanguageManager($this->defaultLanguage->reveal(), $this->configFactory->reveal(), $this->moduleHandler->reveal(), $this->configFactoryOverride->reveal(), $this->requestStack->reveal());
+  }
+
+  /**
+   * @covers ::getCurrentLanguage
+   */
+  public function testCurrentLanguageShouldSupportRecursion() {
+    // Set optional dependencies.
+    $this->languageManager->setNegotiator($this->negotiator->reveal());
+
+    // Mock the config for one configurable language.
+    $config_id = 'foo_bar';
+    $config = $this->prophesize(Config::class);
+    $config->get()->willReturn([
+      'id' => $config_id,
+      'label' => 'Foo Bar',
+      'locked' => FALSE,
+    ]);
+
+    // Mock finding the config that represents configurable languages.
+    $config_ids = [$config_id];
+    $this->configFactory->listAll('language.entity.')->willReturn($config_ids);
+    $this->configFactory->loadMultiple($config_ids)->willReturn([$config]);
+
+    $language_negotiation_method_id = 'foo_bar';
+
+    // Mock the default language.
+    $default_language = $this->prophesize(LanguageInterface::class);
+    $this->defaultLanguage->get()->willReturn($default_language->reveal());
+
+    // Mock the second language type we will test.
+    $expected_second_language = $this->prophesize(LanguageInterface::class);
+    $second_language_type = LanguageInterface::TYPE_URL;
+    $this->negotiator->initializeType($second_language_type)->willReturn([
+      $language_negotiation_method_id => $expected_second_language,
+    ]);
+
+    // Mock the first language type we will test. Note that it depends on the
+    // second language type to create the recursion we are testing.
+    $expected_first_language = $this->prophesize(LanguageInterface::class);
+    $first_language_type = LanguageInterface::TYPE_INTERFACE;
+    $language_manager = $this->languageManager;
+    $this->negotiator->initializeType($first_language_type)->will(function ($type) use ($language_manager, $language_negotiation_method_id, $expected_first_language, $second_language_type) {
+      $language_manager->getCurrentLanguage($second_language_type);
+      return [
+        $language_negotiation_method_id => $expected_first_language,
+      ];
+    });
+
+    $actual_first_language = $this->languageManager->getCurrentLanguage($first_language_type);
+    $this->assertSame($expected_first_language->reveal(), $actual_first_language);
+    $actual_second_language = $this->languageManager->getCurrentLanguage($second_language_type);
+    $this->assertSame($expected_second_language->reveal(), $actual_second_language);
+  }
+
+}
