diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc
index e2836f8..ea3c63a 100644
--- a/core/includes/bootstrap.inc
+++ b/core/includes/bootstrap.inc
@@ -2409,8 +2409,10 @@ function language($type) {
  *   name and its value is its configurability (TRUE/FALSE).
  */
 function language_types_get_all() {
-  return array_keys(variable_get('language_types', language_types_get_default()));
+  $types = \Drupal::config('system.language.types')->get('all');
+  return $types ? $types : array_keys(language_types_get_default());
 }
+
 /**
  * Returns a list of the built-in language types.
  *
diff --git a/core/includes/language.inc b/core/includes/language.inc
index 976dd75..66e1363 100644
--- a/core/includes/language.inc
+++ b/core/includes/language.inc
@@ -15,6 +15,11 @@
 const LANGUAGE_NEGOTIATION_SELECTED = 'language-selected';
 
 /**
+ * The language is determined using the current interface language.
+ */
+const LANGUAGE_NEGOTIATION_INTERFACE = 'language-interface';
+
+/**
  * @defgroup language_negotiation Language Negotiation API functionality
  * @{
  * Functions to customize the language types and the negotiation process.
@@ -52,6 +57,10 @@
  * }
  * @endcode
  *
+ * The locked configuration property prevents one language type from being
+ * switched from customized to not customized, and vice versa.
+ * @see language_types_set()
+ *
  * Every language type can have a different set of language negotiation methods
  * assigned to it. Different language types often share the same language
  * negotiation settings, but they can have independent settings if needed. If
@@ -167,35 +176,12 @@ function language_types_info() {
  * whose language negotiation methods are module-defined and not altered through
  * the user interface.
  *
- * @param $stored
- *   (optional) By default, retrieves values from the 'language_types' variable
- *   to avoid unnecessary hook invocations. If set to FALSE, retrieves values
- *   from the actual language type definitions. This allows reaction to
- *   alterations performed on the definitions by modules installed after the
- *   'language_types' variable is set.
- *
  * @return
  *   An array of language type names.
  */
-function language_types_get_configurable($stored = TRUE) {
-  $configurable = &drupal_static(__FUNCTION__);
-
-  if ($stored && !isset($configurable)) {
-    $types = variable_get('language_types', language_types_get_default());
-    $configurable = array_keys(array_filter($types));
-  }
-
-  if (!$stored) {
-    $result = array();
-    foreach (language_types_info() as $type => $info) {
-      if (!isset($info['fixed'])) {
-        $result[] = $type;
-      }
-    }
-    return $result;
-  }
-
-  return $configurable;
+function language_types_get_configurable() {
+  $configurable = Drupal::config('system.language.types')->get('configurable');
+  return $configurable ? $configurable : array();
 }
 
 /**
@@ -205,48 +191,67 @@ function language_types_get_configurable($stored = TRUE) {
  *   An array of language types.
  */
 function language_types_disable($types) {
-  $enabled_types = variable_get('language_types', language_types_get_default());
-
-  foreach ($types as $type) {
-    unset($enabled_types[$type]);
-  }
-
-  variable_set('language_types', $enabled_types);
+  $configurable = language_types_get_configurable();
+  config('system.language.types')->set('configurable', array_diff($configurable, $types))->save();
 }
 
 /**
  * Updates the language type configuration.
+ *
+ * @param array $customized_language_types
+ *   The configuration object containing the user defined preferences for
+ *   language type customizability.
  */
-function language_types_set() {
+function language_types_set(array $customized_language_types) {
   // Ensure that we are getting the defined language negotiation information. An
   // invocation of module_enable() or module_disable() could outdate the cached
   // information.
   drupal_static_reset('language_types_info');
   drupal_static_reset('language_negotiation_info');
+  $config_values = array();
 
-  // 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();
   $negotiation_info = language_negotiation_info();
-  foreach (language_types_info() as $type => $info) {
-    if (isset($info['fixed'])) {
-      $language_types[$type] = FALSE;
-      $method_weights = array();
-      foreach ($info['fixed'] as $weight => $method_id) {
-        if (isset($negotiation_info[$method_id])) {
-          $method_weights[$method_id] = $weight;
-        }
+  $language_types_info = language_types_info();
+  foreach ($language_types_info as $type => $info) {
+    $customized[$type] = in_array($type, $customized_language_types);
+    // Check if the language is locked. The configuration of a locked language
+    // type cannot be changed using the UI.
+    if (empty($info['locked'])) {
+      // The configuration of unlocked languages set using the UI. Save this
+      // data to the $customized array (stored in configuration).
+      if ($customized[$type] && empty($info['fixed'])) {
+        // If the language is not configurable and there is no default language
+        // negotiation setting then provide one.
+        $method_weights = array(LANGUAGE_NEGOTIATION_INTERFACE);
+        $method_weights = array_flip($method_weights);
+        language_negotiation_set($type, $method_weights);
       }
-      language_negotiation_set($type, $method_weights);
     }
     else {
-      $language_types[$type] = TRUE;
+      // Locked languages don't allow changing their configurable state.
+
+      // Default language negotiation is stored in $info['fixed']. Locked
+      // language types with a default value are not configurable. Locked
+      // language types without a default value are always configurable.
+      $customized[$type] = empty($info['fixed']);
+
+      if (!empty($info['fixed'])) {
+        // Set the language negotiation for non configurable types to use the
+        // default settings stored in $info['fixed'].
+        $method_weights = array();
+        foreach ($info['fixed'] as $weight => $method_id) {
+          if (isset($negotiation_info[$method_id])) {
+            $method_weights[$method_id] = $weight;
+          }
+        }
+        language_negotiation_set($type, $method_weights);
+      }
     }
   }
 
   // Save enabled language types.
-  variable_set('language_types', $language_types);
+  config('system.language.types')->set('configurable', array_keys(array_filter($customized)))->save();
+  config('system.language.types')->set('all', array_keys($language_types_info))->save();
 
   // Ensure that subsequent calls of language_types_get_configurable() return
   // the updated language type information.
@@ -367,7 +372,7 @@ function language_negotiation_set($type, $method_weights) {
 
   $negotiation = array();
   $negotiation_info = language_negotiation_info();
-  $default_types = language_types_get_configurable(FALSE);
+  $default_types = language_types_get_configurable();
 
   // Order the language negotiation method list by weight.
   asort($method_weights);
diff --git a/core/lib/Drupal/Core/Language/LanguageManager.php b/core/lib/Drupal/Core/Language/LanguageManager.php
index d13f6f6..a17ea10 100644
--- a/core/lib/Drupal/Core/Language/LanguageManager.php
+++ b/core/lib/Drupal/Core/Language/LanguageManager.php
@@ -146,7 +146,7 @@ public function isMultilingual() {
    *   An array of all language types.
    */
   protected function getLanguageTypes() {
-    return array_keys(variable_get('language_types', language_types_get_default()));
+    return language_types_get_all();
   }
 
   /**
diff --git a/core/modules/content_translation/content_translation.module b/core/modules/content_translation/content_translation.module
index 84fbed5..531209e 100644
--- a/core/modules/content_translation/content_translation.module
+++ b/core/modules/content_translation/content_translation.module
@@ -64,8 +64,9 @@ function content_translation_module_implements_alter(&$implementations, $hook) {
  * Implements hook_language_type_info_alter().
  */
 function content_translation_language_types_info_alter(array &$language_types) {
-  // Make content language negotiation configurable by removing its predefined
-  // configuration.
+  // Make content language negotiation configurable by removing the 'locked'
+  // flag.
+  $language_types[Language::TYPE_CONTENT]['locked'] = FALSE;
   unset($language_types[Language::TYPE_CONTENT]['fixed']);
 }
 
diff --git a/core/modules/language/language.admin.inc b/core/modules/language/language.admin.inc
index a7c6663..b5d3560 100644
--- a/core/modules/language/language.admin.inc
+++ b/core/modules/language/language.admin.inc
@@ -358,11 +358,17 @@ function language_negotiation_configure_form() {
   $form = array(
     '#submit' => array('language_negotiation_configure_form_submit'),
     '#theme' => 'language_negotiation_configure_form',
-    '#language_types' => language_types_get_configurable(FALSE),
     '#language_types_info' => language_types_info(),
     '#language_negotiation_info' => language_negotiation_info(),
   );
-
+  $form['#language_types'] = array();
+  $configurable = config('system.language.types')->get('configurable');
+  foreach ($form['#language_types_info'] as $type => $info) {
+    // Show locked language types only if they are configurable.
+    if (empty($info['locked']) || in_array($type, $configurable)) {
+      $form['#language_types'][] = $type;
+    }
+  }
   foreach ($form['#language_types'] as $type) {
     language_negotiation_configure_form_table($form, $type);
   }
@@ -390,6 +396,21 @@ function language_negotiation_configure_form_table(&$form, $type) {
     '#show_operations' => FALSE,
     'weight' => array('#tree' => TRUE),
   );
+  // Only show configurability checkbox for the unlocked language types.
+  if (empty($info['locked'])) {
+    $configurable = config('system.language.types')->get('configurable');
+    $table_form['configurable'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Customize %language_name language detection to differ from User interface text language detection settings.', array('%language_name' => $info['name'])),
+      '#default_value' => in_array($type, $configurable),
+      '#attributes' => array('class' => array('language-customization-checkbox')),
+      '#attached' => array(
+        'library' => array(
+          array('language', 'language.admin')
+        ),
+      ),
+    );
+  }
 
   $negotiation_info = $form['#language_negotiation_info'];
   $enabled_methods = variable_get("language_negotiation_$type", array());
@@ -521,12 +542,13 @@ function theme_language_negotiation_configure_form($variables) {
       '#rows' => $rows,
       '#attributes' => array('id' => "language-negotiation-methods-$type"),
     );
-    $table  = drupal_render($build);
+    $table  = drupal_render($form[$type]['configurable']);
+    $table .= drupal_render($build);
     $table .= drupal_render_children($form[$type]);
 
     drupal_add_tabledrag("language-negotiation-methods-$type", 'order', 'sibling', "language-method-weight-$type");
 
-    $output .= '<div class="form-item">' . $title . $description . $table . '</div>';
+    $output .= '<div class="form-item table-language-group table-' . $type . '-wrapper">' . $title . $description . $table . '</div>';
   }
 
   $output .= drupal_render_children($form);
@@ -539,11 +561,19 @@ function theme_language_negotiation_configure_form($variables) {
 function language_negotiation_configure_form_submit($form, &$form_state) {
   $configurable_types = $form['#language_types'];
 
+  $configurable = config('system.language.types')->get('configurable');
+  $config_values = array();
+  $method_weights_type = array();
+
   foreach ($configurable_types as $type) {
+    $config_values[$type] = in_array($type, $configurable);
     $method_weights = array();
     $enabled_methods = $form_state['values'][$type]['enabled'];
     $enabled_methods[LANGUAGE_NEGOTIATION_SELECTED] = TRUE;
     $method_weights_input = $form_state['values'][$type]['weight'];
+    if (isset($form_state['values'][$type]['configurable'])) {
+      $config_values[$type] = !empty($form_state['values'][$type]['configurable']);
+    }
 
     foreach ($method_weights_input as $method_id => $weight) {
       if ($enabled_methods[$method_id]) {
@@ -551,13 +581,28 @@ function language_negotiation_configure_form_submit($form, &$form_state) {
       }
     }
 
-    language_negotiation_set($type, $method_weights);
+    $method_weights_type[$type] = $method_weights;
     variable_set("language_negotiation_methods_weight_$type", $method_weights_input);
   }
 
   // Update non-configurable language types and the related language negotiation
   // configuration.
-  language_types_set();
+  language_types_set(array_keys(array_filter($config_values)));
+
+  // Update the language negotiations after setting the configurability.
+  foreach ($method_weights_type as $type => $method_weights) {
+    language_negotiation_set($type, $method_weights);
+  }
+
+  // Clear block definitions cache since the available blocks and their names
+  // may have been changed based on the configurable types.
+  if (module_exists('block')) {
+    // If there is an active language switcher for a language type that has been
+    // made not configurable, deactivate it first.
+    $non_configurable = array_keys(array_diff($config_values, array_filter($config_values)));
+    _language_disable_language_switcher($non_configurable);
+    Drupal::service('plugin.manager.block')->clearCachedDefinitions();
+  }
 
   $form_state['redirect'] = 'admin/config/regional/language/detection';
   drupal_set_message(t('Language negotiation configuration saved.'));
@@ -941,3 +986,21 @@ function language_content_settings_form_submit(array $form, array &$form_state)
   }
   drupal_set_message(t('Settings successfully updated.'));
 }
+
+/**
+ * Helper function to disable the language switcher blocks.
+ *
+ * @param array $language_types
+ *   Array containing all language types whose language switchers need to be
+ *   disabled.
+ */
+function _language_disable_language_switcher(array $language_types) {
+  $blocks = _block_rehash();
+  foreach ($language_types as $language_type) {
+    foreach ($blocks as $block) {
+      if (strpos($block->id, 'language_switcher_' . substr($language_type, 9)) !== FALSE) {
+        $block->delete();
+      }
+    }
+  }
+}
diff --git a/core/modules/language/language.admin.js b/core/modules/language/language.admin.js
new file mode 100644
index 0000000..7e974b0
--- /dev/null
+++ b/core/modules/language/language.admin.js
@@ -0,0 +1,32 @@
+(function ($, Drupal) {
+
+"use strict";
+
+/**
+ * Makes language negotiation inherit user interface negotiation.
+ */
+Drupal.behaviors.negotiationLanguage = {
+  attach: function () {
+    var $configForm = $('#language-negotiation-configure-form');
+    var inputSelector = 'input[name$="[configurable]"]';
+    // Given a customization checkbox derive the language type being changed.
+    function toggleTable (checkbox) {
+      var $checkbox = $(checkbox);
+      // Get the language detection type such as User interface text language
+      // detection or Content language detection.
+      $checkbox.closest('.table-language-group')
+        .find('table, .tabledrag-toggle-weight')
+          .toggle($checkbox.prop('checked'));
+    }
+    // Bind hide/show and rearrange customization checkboxes.
+    $configForm.once('negotiation-language-admin-bind').on('change', inputSelector, function (event) {
+      toggleTable(event.target);
+    });
+    // Initially, hide language detection types that are not customized.
+    $configForm.find(inputSelector + ':not(:checked)').each(function (index, element) {
+      toggleTable(element);
+    });
+  }
+};
+
+})(jQuery, Drupal);
diff --git a/core/modules/language/language.install b/core/modules/language/language.install
index 066ef26..9f74b97 100644
--- a/core/modules/language/language.install
+++ b/core/modules/language/language.install
@@ -17,7 +17,7 @@
 function language_install() {
   // Enable URL language detection for each configurable language type.
   require_once DRUPAL_ROOT . '/core/includes/language.inc';
-  foreach (language_types_get_configurable(FALSE) as $type) {
+  foreach (language_types_get_configurable() as $type) {
     language_negotiation_set($type, array(LANGUAGE_NEGOTIATION_URL => 0));
   }
 }
diff --git a/core/modules/language/language.module b/core/modules/language/language.module
index bdbd15c..4dc690a 100644
--- a/core/modules/language/language.module
+++ b/core/modules/language/language.module
@@ -591,6 +591,26 @@ function language_delete($langcode) {
 }
 
 /**
+ * Implements hook_library_info().
+ */
+function language_library_info() {
+  $libraries['language.admin'] = array(
+    'title' => 'Language detection admin',
+    'version' => VERSION,
+    'js' => array(
+      drupal_get_path('module', 'language') . '/language.admin.js' => array(),
+    ),
+    'dependencies' => array(
+      array('system', 'jquery'),
+      array('system', 'drupal'),
+      array('system', 'jquery.once'),
+    ),
+  );
+
+  return $libraries;
+}
+
+/**
  * Implements hook_language_types_info().
  *
  * Defines the three core language types:
@@ -611,14 +631,17 @@ function language_language_types_info() {
     Language::TYPE_INTERFACE => array(
       'name' => t('User interface text'),
       'description' => t('Order of language detection methods for user interface text. If a translation of user interface text is available in the detected language, it will be displayed.'),
+      'locked' => TRUE,
     ),
     Language::TYPE_CONTENT => array(
       'name' => t('Content'),
       'description' => t('Order of language detection methods for content. If a version of content is available in the detected language, it will be displayed.'),
       'fixed' => array(LANGUAGE_NEGOTIATION_INTERFACE),
+      'locked' => TRUE,
     ),
     Language::TYPE_URL => array(
       'fixed' => array(LANGUAGE_NEGOTIATION_URL, LANGUAGE_NEGOTIATION_URL_FALLBACK),
+      'locked' => TRUE,
     ),
   );
 }
@@ -717,8 +740,10 @@ function language_negotiation_include() {
  * Implements hook_modules_enabled().
  */
 function language_modules_enabled($modules) {
-  language_negotiation_include();
-  language_types_set();
+  include_once DRUPAL_ROOT . '/core/includes/language.inc';
+  // Load configurability options from configuration.
+  $configurable = config('system.language.types')->get('configurable');
+  language_types_set($configurable);
   language_negotiation_purge();
 }
 
diff --git a/core/modules/language/language.negotiation.inc b/core/modules/language/language.negotiation.inc
index c4e97b3..78b9d27 100644
--- a/core/modules/language/language.negotiation.inc
+++ b/core/modules/language/language.negotiation.inc
@@ -20,11 +20,6 @@
 const LANGUAGE_NEGOTIATION_BROWSER = 'language-browser';
 
 /**
- * The language is determined using the current interface language.
- */
-const LANGUAGE_NEGOTIATION_INTERFACE = 'language-interface';
-
-/**
  * If no URL language, language is determined using an already detected one.
  */
 const LANGUAGE_NEGOTIATION_URL_FALLBACK = 'language-url-fallback';
diff --git a/core/modules/language/lib/Drupal/language/Plugin/Derivative/LanguageBlock.php b/core/modules/language/lib/Drupal/language/Plugin/Derivative/LanguageBlock.php
index ee52336..a329c3b 100644
--- a/core/modules/language/lib/Drupal/language/Plugin/Derivative/LanguageBlock.php
+++ b/core/modules/language/lib/Drupal/language/Plugin/Derivative/LanguageBlock.php
@@ -19,11 +19,17 @@ class LanguageBlock extends DerivativeBase {
   public function getDerivativeDefinitions(array $base_plugin_definition) {
     include_once DRUPAL_ROOT . '/core/includes/language.inc';
     $info = language_types_info();
-    foreach (language_types_get_configurable(FALSE) as $type) {
+    $configurable_types = language_types_get_configurable();
+    foreach ($configurable_types as $type) {
       $this->derivatives[$type] = $base_plugin_definition;
       $this->derivatives[$type]['admin_label'] = t('Language switcher (!type)', array('!type' => $info[$type]['name']));
       $this->derivatives[$type]['cache'] = DRUPAL_NO_CACHE;
     }
+    // If there is just one configurable type then change the title of the
+    // block.
+    if (count($configurable_types) == 1) {
+      $this->derivatives[reset($configurable_types)]['admin_label'] = t('Language switcher');
+    }
     return parent::getDerivativeDefinitions($base_plugin_definition);
   }
 }
diff --git a/core/modules/language/lib/Drupal/language/Tests/LanguageNegotiationInfoTest.php b/core/modules/language/lib/Drupal/language/Tests/LanguageNegotiationInfoTest.php
index e580e5c..a07d8a0 100644
--- a/core/modules/language/lib/Drupal/language/Tests/LanguageNegotiationInfoTest.php
+++ b/core/modules/language/lib/Drupal/language/Tests/LanguageNegotiationInfoTest.php
@@ -56,8 +56,8 @@ function testInfoAlterations() {
     \Drupal::state()->set('language_test.content_language_type', TRUE);
     $this->languageNegotiationUpdate();
     $type = Language::TYPE_CONTENT;
-    $language_types = variable_get('language_types', language_types_get_default());
-    $this->assertTrue($language_types[$type], 'Content language type is configurable.');
+    $language_types = language_types_get_configurable();
+    $this->assertTrue(in_array($type, $language_types), 'Content language type is configurable.');
 
     // Enable some core and custom language negotiation methods. The test
     // language type is supposed to be configurable.
@@ -69,6 +69,7 @@ function testInfoAlterations() {
       $form_field => TRUE,
       $type . '[enabled][' . $test_method_id . ']' => TRUE,
       $test_type . '[enabled][' . $test_method_id . ']' => TRUE,
+      $test_type . '[configurable]' => TRUE,
     );
     $this->drupalPost('admin/config/regional/language/detection', $edit, t('Save settings'));
 
@@ -158,8 +159,9 @@ protected function languageNegotiationUpdate($op = 'enable') {
    */
   protected function checkFixedLanguageTypes() {
     drupal_static_reset('language_types_info');
+    $configurable = language_types_get_configurable();
     foreach (language_types_info() as $type => $info) {
-      if (isset($info['fixed'])) {
+      if (!in_array($type, $configurable) && isset($info['fixed'])) {
         $negotiation = variable_get("language_negotiation_$type", array());
         $equal = count($info['fixed']) == count($negotiation);
         while ($equal && list($id) = each($negotiation)) {
diff --git a/core/modules/language/tests/language_test/language_test.module b/core/modules/language/tests/language_test/language_test.module
index 3cb6f6b..267cdf3 100644
--- a/core/modules/language/tests/language_test/language_test.module
+++ b/core/modules/language/tests/language_test/language_test.module
@@ -32,6 +32,7 @@ function language_test_language_types_info() {
       ),
       'fixed_test_language_type' => array(
         'fixed' => array('test_language_negotiation_method'),
+        'locked' => TRUE,
       ),
     );
   }
@@ -42,7 +43,15 @@ function language_test_language_types_info() {
  */
 function language_test_language_types_info_alter(array &$language_types) {
   if (Drupal::state()->get('language_test.content_language_type')) {
+    $language_types[Language::TYPE_CONTENT]['locked'] = FALSE;
     unset($language_types[Language::TYPE_CONTENT]['fixed']);
+    // By default languages are not configurable. Make Language::TYPE_CONTENT
+    // configurable.
+    $configurable = config('system.language.types')->get('configurable');
+    if (!in_array(Language::TYPE_CONTENT, $configurable)) {
+      $configurable[] = Language::TYPE_CONTENT;
+      config('system.language.types')->set('configurable', $configurable)->save();
+    }
   }
 }
 
@@ -87,6 +96,7 @@ function language_test_language_negotiation_info_alter(array &$negotiation_info)
  */
 function language_test_store_language_negotiation() {
   $last = array();
+  print_r(language_types_get_all());
   foreach (language_types_get_all() as $type) {
     $last[$type] = language($type)->id;
   }
diff --git a/core/modules/locale/lib/Drupal/locale/Tests/LocaleUninstallTest.php b/core/modules/locale/lib/Drupal/locale/Tests/LocaleUninstallTest.php
index c53ed7a..961a5dd 100644
--- a/core/modules/locale/lib/Drupal/locale/Tests/LocaleUninstallTest.php
+++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleUninstallTest.php
@@ -96,7 +96,7 @@ function testUninstallProcess() {
 
     // Change language negotiation options.
     drupal_load('module', 'locale');
-    variable_set('language_types', language_types_get_default() + array('language_custom' => TRUE));
+    \Drupal::config('system.language.types')->set('configurable', language_types_get_default() + array('language_custom' => TRUE))->save();
     variable_set('language_negotiation_' . Language::TYPE_INTERFACE, language_language_negotiation_info());
     variable_set('language_negotiation_' . Language::TYPE_CONTENT, language_language_negotiation_info());
     variable_set('language_negotiation_' . Language::TYPE_URL, language_language_negotiation_info());
diff --git a/core/modules/system/config/system.language.types.yml b/core/modules/system/config/system.language.types.yml
new file mode 100644
index 0000000..3eba117
--- /dev/null
+++ b/core/modules/system/config/system.language.types.yml
@@ -0,0 +1,7 @@
+all:
+  - language_interface
+  - language_content
+  - language_url
+
+configurable:
+  - language_interface
diff --git a/core/modules/system/language.api.php b/core/modules/system/language.api.php
index d01df59..9fe910a 100644
--- a/core/modules/system/language.api.php
+++ b/core/modules/system/language.api.php
@@ -44,10 +44,16 @@ function hook_language_switch_links_alter(array &$links, $type, $path) {
  *   may contain the following elements:
  *   - name: The human-readable language type identifier.
  *   - description: A description of the language type.
+ *   - locked: A boolean indicating if the user can choose wether to configure
+ *     the language type or not using the UI.
  *   - fixed: A fixed array of language negotiation method identifiers to use to
- *     initialize this language. Defining this key makes the language type
- *     non-configurable, so it will always use the specified methods in the
- *     given priority order. Omit to make the language type configurable.
+ *     initialize this language. If locked is set to TRUE and fixed is set, it
+ *     will always use the specified methods in the given priority order. If not
+ *     present and locked is TRUE then LANGUAGE_NEGOTIATION_INTERFACE will be
+ *     used.
+ *
+ *  @todo Rename the 'fixed' key to something more meaningful, for instance
+ *     'negotiation settings'.
  *
  * @see hook_language_types_info_alter()
  * @ingroup language_negotiation
@@ -57,8 +63,10 @@ function hook_language_types_info() {
     'custom_language_type' => array(
       'name' => t('Custom language'),
       'description' => t('A custom language type.'),
+      'locked' => FALSE,
     ),
     'fixed_custom_language_type' => array(
+      'locked' => TRUE,
       'fixed' => array('custom_language_negotiation_method'),
     ),
   );
diff --git a/core/modules/system/lib/Drupal/system/Tests/Common/JavaScriptTest.php b/core/modules/system/lib/Drupal/system/Tests/Common/JavaScriptTest.php
index 099d911..5a1d3f6 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Common/JavaScriptTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Common/JavaScriptTest.php
@@ -543,7 +543,7 @@ function testGetLibrary() {
     $this->assertTrue(isset($libraries['jquery.farbtastic']), 'Retrieved all module libraries.');
     // Retrieve all libraries for a module not implementing hook_library_info().
     // Note: This test installs language module.
-    $libraries = drupal_get_library('language');
+    $libraries = drupal_get_library('dblog');
     $this->assertEqual($libraries, array(), 'Retrieving libraries from a module not implementing hook_library_info() returns an emtpy array.');
 
     // Retrieve a specific library by module and name.
diff --git a/core/modules/system/system.install b/core/modules/system/system.install
index f10d86b..89f9ddc 100644
--- a/core/modules/system/system.install
+++ b/core/modules/system/system.install
@@ -2241,6 +2241,19 @@ function system_update_8058() {
 }
 
 /**
+ * Move variable language_types to config.
+ *
+ * @ingroup config_upgrade
+ */
+function system_update_8059() {
+  update_variables_to_config('system.language.types', array(
+    'language_interface' => 'configurable.language_interface',
+    'language_content' => 'configurable.language_content',
+    'language_url' => 'configurable.language_content',
+  ));
+}
+
+/**
  * @} End of "defgroup updates-7.x-to-8.x".
  * The next series of updates should start at 9000.
  */
