diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc
index ab06260..7d5451d 100644
--- a/core/includes/bootstrap.inc
+++ b/core/includes/bootstrap.inc
@@ -2609,7 +2609,7 @@ function get_t() {
  * Initializes all the defined language types.
  */
 function drupal_language_initialize() {
-  $types = language_types();
+  $types = language_types_get_all();
 
   // Ensure the language is correctly returned, even without multilanguage
   // support. Also make sure we have a $language fallback, in case a language
@@ -2622,7 +2622,7 @@ function drupal_language_initialize() {
   if (language_multilingual()) {
     include_once DRUPAL_ROOT . '/core/includes/language.inc';
     foreach ($types as $type) {
-      $GLOBALS[$type] = language_initialize($type);
+      $GLOBALS[$type] = language_types_initialize($type);
     }
     // Allow modules to react on language system initialization in multilingual
     // environments.
@@ -2631,13 +2631,19 @@ function drupal_language_initialize() {
 }
 
 /**
+ * Returns an array of the available language types.
+ */
+function language_types_get_all() {
+  return array_keys(variable_get('language_types', language_types_get_default()));
+}
+/**
  * Returns a list of the built-in language types.
  *
  * @return
- *   An array of key-values pairs where the key is the language type and the
- *   value is its configurability.
+ *   An array of key-values pairs where the key is the language type name and
+ *   the value is its configurability (TRUE/FALSE).
  */
-function drupal_language_types() {
+function language_types_get_default() {
   return array(
     LANGUAGE_TYPE_INTERFACE => TRUE,
     LANGUAGE_TYPE_CONTENT => FALSE,
@@ -2656,13 +2662,6 @@ function language_multilingual() {
 }
 
 /**
- * Returns an array of the available language types.
- */
-function language_types() {
-  return array_keys(variable_get('language_types', drupal_language_types()));
-}
-
-/**
  * Returns a list of configured languages.
  *
  * @param $only_enabled
diff --git a/core/includes/common.inc b/core/includes/common.inc
index a4fcf51..0d28030 100644
--- a/core/includes/common.inc
+++ b/core/includes/common.inc
@@ -6190,7 +6190,7 @@ function drupal_render_cid_parts($granularity = NULL) {
   // If Locale is enabled but we have only one language we do not need it as cid
   // part.
   if (language_multilingual()) {
-    foreach (language_types_configurable() as $language_type) {
+    foreach (language_types_get_configurable() as $language_type) {
       $cid_parts[] = $GLOBALS[$language_type]->langcode;
     }
   }
diff --git a/core/includes/language.inc b/core/includes/language.inc
index 4628053..f12f34a 100644
--- a/core/includes/language.inc
+++ b/core/includes/language.inc
@@ -11,11 +11,42 @@
 const LANGUAGE_NEGOTIATION_DEFAULT = 'language-default';
 
 /**
- * Return all the defined language types.
+ * Chooses a language for the given type based on language negotiation settings.
+ *
+ * @param $type
+ *   The language type key.
+ *
+ * @return
+ *   The negotiated language object.
+ */
+function language_types_initialize($type) {
+  // Execute the language providers in the order they were set up and return the
+  // first valid language found.
+  $negotiation = variable_get("language_negotiation_$type", array());
+
+  foreach ($negotiation as $provider_id => $provider) {
+    $language = language_provider_invoke($provider_id, $provider);
+    if ($language) {
+      // Remember the provider key used to detect the language.
+      $language->provider = $provider_id;
+      return $language;
+    }
+  }
+
+  // If no other language was found use the default one.
+  $language = language_default();
+  $language->provider = LANGUAGE_NEGOTIATION_DEFAULT;
+  return $language;
+}
+
+/**
+ * Returns information about all defined language types.
  *
  * @return
- *   An array of language type names. The name will be used as the global
- *   variable name the language value will be stored in.
+ *   An associative array of language type information arrays keyed by type
+ *   names. Based on information from hook_language_types_info().
+ *
+ * @see hook_language_types_info().
  */
 function language_types_info() {
   $language_types = &drupal_static(__FUNCTION__);
@@ -30,7 +61,7 @@ function language_types_info() {
 }
 
 /**
- * Return only the configurable language types.
+ * Returns only the configurable language types.
  *
  * A language type maybe configurable or fixed. A fixed language type is a type
  * whose negotiation values are unchangeable and defined while defining the
@@ -46,11 +77,11 @@ function language_types_info() {
  * @return
  *   An array of language type names.
  */
-function language_types_configurable($stored = TRUE) {
+function language_types_get_configurable($stored = TRUE) {
   $configurable = &drupal_static(__FUNCTION__);
 
   if ($stored && !isset($configurable)) {
-    $types = variable_get('language_types', drupal_language_types());
+    $types = variable_get('language_types', language_types_get_default());
     $configurable = array_keys(array_filter($types));
   }
 
@@ -74,7 +105,7 @@ function language_types_configurable($stored = TRUE) {
  *   An array of language types.
  */
 function language_types_disable($types) {
-  $enabled_types = variable_get('language_types', drupal_language_types());
+  $enabled_types = variable_get('language_types', language_types_get_default());
 
   foreach ($types as $type) {
     unset($enabled_types[$type]);
@@ -96,6 +127,7 @@ function language_types_set() {
   // Determine which language types are configurable and which not by checking
   // whether the 'fixed' key is defined. Non-configurable (fixed) language types
   // have their language negotiation settings stored there.
+  $language_types = array();
   $defined_providers = language_negotiation_info();
   foreach (language_types_info() as $type => $info) {
     if (isset($info['fixed'])) {
@@ -113,12 +145,12 @@ function language_types_set() {
     }
   }
 
-  // Save language types.
+  // Save enabled language types.
   variable_set('language_types', $language_types);
 
-  // Ensure that subsequent calls of language_types_configurable() return the
-  // updated language type information.
-  drupal_static_reset('language_types_configurable');
+  // Ensure that subsequent calls of language_types_get_configurable() return
+  // the updated language type information.
+  drupal_static_reset('language_types_get_configurable');
 }
 
 /**
@@ -166,7 +198,7 @@ function language_negotiation_get($type, $provider_id = NULL) {
  *   provider is enabled, FALSE otherwise.
  */
 function language_negotiation_get_any($provider_id) {
-  foreach (language_types_configurable() as $type) {
+  foreach (language_types_get_configurable() as $type) {
     if (language_negotiation_get($type, $provider_id)) {
       return TRUE;
     }
@@ -250,7 +282,7 @@ function language_negotiation_set($type, $language_providers) {
   $negotiation = array();
   $providers_weight = array();
   $defined_providers = language_negotiation_info();
-  $default_types = language_types_configurable(FALSE);
+  $default_types = language_types_get_configurable(FALSE);
 
   // Initialize the providers weight list.
   foreach ($language_providers as $id => $provider) {
@@ -370,34 +402,6 @@ function language_provider_weight($provider) {
 }
 
 /**
- * Choose a language for the given type based on language negotiation settings.
- *
- * @param $type
- *   The language type.
- *
- * @return
- *   The negotiated language object.
- */
-function language_initialize($type) {
-  // Execute the language providers in the order they were set up and return the
-  // first valid language found.
-  $negotiation = variable_get("language_negotiation_$type", array());
-
-  foreach ($negotiation as $provider_id => $provider) {
-    $language = language_provider_invoke($provider_id, $provider);
-    if ($language) {
-      $language->provider = $provider_id;
-      return $language;
-    }
-  }
-
-  // If no other language was found use the default one.
-  $language = language_default();
-  $language->provider = LANGUAGE_NEGOTIATION_DEFAULT;
-  return $language;
-}
-
-/**
  * Default language provider.
  *
  * @return
diff --git a/core/includes/update.inc b/core/includes/update.inc
index 9dd1e5d..be9788f 100644
--- a/core/includes/update.inc
+++ b/core/includes/update.inc
@@ -138,7 +138,7 @@ function update_prepare_d8_bootstrap() {
  */
 function update_prepare_stored_includes() {
   // Update language negotiation settings.
-  foreach (language_types() as $language_type) {
+  foreach (language_types_get_all() as $language_type) {
     $negotiation = variable_get("language_negotiation_$language_type", array());
     foreach ($negotiation as $id => &$provider) {
       if (isset($negotiation[$id]['file']) && $negotiation[$id]['file'] == 'includes/locale.inc') {
diff --git a/core/modules/locale/locale.admin.inc b/core/modules/locale/locale.admin.inc
index 072dba1..2c78e17 100644
--- a/core/modules/locale/locale.admin.inc
+++ b/core/modules/locale/locale.admin.inc
@@ -14,7 +14,7 @@ function language_negotiation_configure_form() {
   $form = array(
     '#submit' => array('language_negotiation_configure_form_submit'),
     '#theme' => 'language_negotiation_configure_form',
-    '#language_types' => language_types_configurable(FALSE),
+    '#language_types' => language_types_get_configurable(FALSE),
     '#language_types_info' => language_types_info(),
     '#language_providers' => language_negotiation_info(),
   );
diff --git a/core/modules/locale/locale.api.php b/core/modules/locale/locale.api.php
index 4ed22a8..1fb5973 100644
--- a/core/modules/locale/locale.api.php
+++ b/core/modules/locale/locale.api.php
@@ -65,13 +65,19 @@ function hook_language_switch_links_alter(array &$links, $type, $path) {
  * Allow modules to define their own language types.
  *
  * @return
- *   An array of language type definitions. Each language type has an identifier
- *   key. The language type definition is an associative array that may contain
- *   the following key-value pairs:
+ *   An associative array of language type definitions.
+ *
+ *   Each language type has an identifier key which is used as the name for the
+ *   global variable corresponding to the language type in the bootstrap phase.
+ *
+ *   The language type definition is an associative array that may contain the
+ *   following key-value pairs:
  *   - "name": The human-readable language type identifier.
  *   - "description": A description of the language type.
- *   - "fixed": An array of language provider identifiers. Defining this key
- *     makes the language type non-configurable.
+ *   - "fixed": A fixed array of language provider identifiers to use to
+ *     initialize this language. Defining this key makes the language type
+ *     non-configurable and will always use the specified providers in the given
+ *     priority order.
  */
 function hook_language_types_info() {
   return array(
@@ -88,6 +94,8 @@ function hook_language_types_info() {
 /**
  * Perform alterations on language types.
  *
+ * @see hook_language_types_info().
+ *
  * @param $language_types
  *   Array of language type definitions.
  */
diff --git a/core/modules/locale/locale.install b/core/modules/locale/locale.install
index 0ee7907..c4fc445 100644
--- a/core/modules/locale/locale.install
+++ b/core/modules/locale/locale.install
@@ -29,7 +29,7 @@ function locale_install() {
   }
 
   // Enable URL language detection for each (core) configurable language type.
-  foreach (language_types_configurable() as $type) {
+  foreach (language_types_get_configurable() as $type) {
     variable_set("language_negotiation_$type", $negotiation);
   }
 }
@@ -97,7 +97,7 @@ function locale_uninstall() {
   variable_del('locale_translation_plurals');
   variable_del('locale_translation_javascript');
 
-  foreach (language_types() as $type) {
+  foreach (language_types_get_all() as $type) {
     variable_del("language_negotiation_$type");
     variable_del("locale_language_providers_weight_$type");
   }
diff --git a/core/modules/locale/locale.module b/core/modules/locale/locale.module
index 1f3c775..e759aad 100644
--- a/core/modules/locale/locale.module
+++ b/core/modules/locale/locale.module
@@ -906,7 +906,7 @@ function locale_block_info() {
   include_once DRUPAL_ROOT . '/core/includes/language.inc';
   $block = array();
   $info = language_types_info();
-  foreach (language_types_configurable(FALSE) as $type) {
+  foreach (language_types_get_configurable(FALSE) as $type) {
     $block[$type] = array(
       'info' => t('Language switcher (@type)', array('@type' => $info[$type]['name'])),
       // Not worth caching.
@@ -964,7 +964,7 @@ function locale_url_outbound_alter(&$path, &$options, $original_path) {
       $callbacks = array();
       include_once DRUPAL_ROOT . '/core/includes/language.inc';
 
-      foreach (language_types_configurable() as $type) {
+      foreach (language_types_get_configurable() as $type) {
         // Get url rewriter callbacks only from enabled language providers.
         $negotiation = variable_get("language_negotiation_$type", array());
 
diff --git a/core/modules/locale/locale.test b/core/modules/locale/locale.test
index 0ba8469..2e0023e 100644
--- a/core/modules/locale/locale.test
+++ b/core/modules/locale/locale.test
@@ -1128,7 +1128,7 @@ class LocaleUninstallFunctionalTest extends DrupalWebTestCase {
 
     // Change language negotiation options.
     drupal_load('module', 'locale');
-    variable_set('language_types', drupal_language_types() + array('language_custom' => TRUE));
+    variable_set('language_types', language_types_get_default() + array('language_custom' => TRUE));
     variable_set('language_negotiation_' . LANGUAGE_TYPE_INTERFACE, locale_language_negotiation_info());
     variable_set('language_negotiation_' . LANGUAGE_TYPE_CONTENT, locale_language_negotiation_info());
     variable_set('language_negotiation_' . LANGUAGE_TYPE_URL, locale_language_negotiation_info());
@@ -1157,7 +1157,7 @@ class LocaleUninstallFunctionalTest extends DrupalWebTestCase {
 
     // Check language negotiation.
     require_once DRUPAL_ROOT . '/core/includes/language.inc';
-    $this->assertTrue(count(language_types()) == count(drupal_language_types()), t('Language types reset'));
+    $this->assertTrue(count(language_types_get_all()) == count(language_types_get_default()), t('Language types reset'));
     $language_negotiation = language_negotiation_get(LANGUAGE_TYPE_INTERFACE) == LANGUAGE_NEGOTIATION_DEFAULT;
     $this->assertTrue($language_negotiation, t('Interface language negotiation: %setting', array('%setting' => t($language_negotiation ? 'none' : 'set'))));
     $language_negotiation = language_negotiation_get(LANGUAGE_TYPE_CONTENT) == LANGUAGE_NEGOTIATION_DEFAULT;
@@ -2676,7 +2676,7 @@ class LocaleLanguageNegotiationInfoFunctionalTest extends DrupalWebTestCase {
     variable_set('locale_test_content_language_type', TRUE);
     $this->languageNegotiationUpdate();
     $type = LANGUAGE_TYPE_CONTENT;
-    $language_types = variable_get('language_types', drupal_language_types());
+    $language_types = variable_get('language_types', language_types_get_default());
     $this->assertTrue($language_types[$type], t('Content language type is configurable.'));
 
     // Enable some core and custom language providers. The test language type is
@@ -2702,7 +2702,7 @@ class LocaleLanguageNegotiationInfoFunctionalTest extends DrupalWebTestCase {
 
     // Check that type-specific language providers can be assigned only to the
     // corresponding language types.
-    foreach (language_types_configurable() as $type) {
+    foreach (language_types_get_configurable() as $type) {
       $form_field = $type . '[enabled][test_language_provider_ts]';
       if ($type == $test_type) {
         $this->assertFieldByXPath("//input[@name=\"$form_field\"]", NULL, t('Type-specific test language provider available for %type.', array('%type' => $type)));
@@ -2715,7 +2715,7 @@ class LocaleLanguageNegotiationInfoFunctionalTest extends DrupalWebTestCase {
     // Check language negotiation results.
     $this->drupalGet('');
     $last = variable_get('locale_test_language_negotiation_last', array());
-    foreach (language_types() as $type) {
+    foreach (language_types_get_all() as $type) {
       $langcode = $last[$type];
       $value = $type == LANGUAGE_TYPE_CONTENT || strpos($type, 'test') !== FALSE ? 'it' : 'en';
       $this->assertEqual($langcode, $value, t('The negotiated language for %type is %language', array('%type' => $type, '%language' => $langcode)));
@@ -2726,7 +2726,7 @@ class LocaleLanguageNegotiationInfoFunctionalTest extends DrupalWebTestCase {
     $this->languageNegotiationUpdate('disable');
 
     // Check that only the core language types are available.
-    foreach (language_types() as $type) {
+    foreach (language_types_get_all() as $type) {
       $this->assertTrue(strpos($type, 'test') === FALSE, t('The %type language is still available', array('%type' => $type)));
     }
 
diff --git a/core/modules/locale/tests/locale_test.module b/core/modules/locale/tests/locale_test.module
index c7bc6e3..92081d1 100644
--- a/core/modules/locale/tests/locale_test.module
+++ b/core/modules/locale/tests/locale_test.module
@@ -94,7 +94,7 @@ function locale_test_language_negotiation_info_alter(array &$language_providers)
  */
 function locale_test_store_language_negotiation() {
   $last = array();
-  foreach (language_types() as $type) {
+  foreach (language_types_get_all() as $type) {
     $last[$type] = $GLOBALS[$type]->langcode;
   }
   variable_set('locale_test_language_negotiation_last', $last);
