diff --git a/core/includes/language.inc b/core/includes/language.inc
index 74d5752..1f7d392 100644
--- a/core/includes/language.inc
+++ b/core/includes/language.inc
@@ -178,19 +178,10 @@ function language_types_info() {
 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;
+  if (!$stored || !isset($configurable)) {
+    $configurable = config('system.language.types')->get('configurable');
+    $configurable = is_null($configurable) ? array() : array_keys(array_filter($configurable));
+    return $configurable;
   }
 
   return $configurable;
@@ -214,37 +205,63 @@ function language_types_disable($types) {
 
 /**
  * Updates the language type configuration.
+ *
+ * @param array $configurable
+ *   The configuration object containing the user defined preferences for
+ *   language type customizability. If it's not provided it will be loaded from
+ *   configuration.
  */
-function language_types_set() {
+function language_types_set($configurable = NULL) {
+  language_negotiation_include();
   // 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');
 
+  // In case the $configurable array is not passed in load it from
+  // configuration.
+  if (is_null($configurable)) {
+    $configurable = config('system.language.types')->get('configurable');
+  }
+
   // 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;
+    if ($locked = !empty($info['locked'])) {
+      // For locked languages the configurability is set based on the presence
+      // of the default settings.
+      $configurable[$type] = empty($info['fixed']);
+      $language_types[$type] = !$locked;
+      if (!$configurable[$type]) {
+        $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);
       }
-      language_negotiation_set($type, $method_weights);
     }
     else {
-      $language_types[$type] = TRUE;
+      // For unlocked languages read the configurable array.
+      $language_types[$type] = !empty($configurable[$type]);
+      if (!$language_types[$type] && empty($info['fixed'])) {
+        // If the language is non 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);
+      }
     }
   }
 
   // Save enabled language types.
   variable_set('language_types', $language_types);
+  config('system.language.types')->set('configurable', $configurable)->save();
 
   // Ensure that subsequent calls of language_types_get_configurable() return
   // the updated language type information.
diff --git a/core/modules/language/language.admin.inc b/core/modules/language/language.admin.inc
index f59fb38..2da053e 100644
--- a/core/modules/language/language.admin.inc
+++ b/core/modules/language/language.admin.inc
@@ -357,11 +357,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 they are configurable.
+    if (empty($info['locked']) || $configurable[$type]) {
+      $form['#language_types'][] = $type;
+    }
+  }
   foreach ($form['#language_types'] as $type) {
     language_negotiation_configure_form_table($form, $type);
   }
@@ -389,6 +395,19 @@ 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' => !empty($configurable[$type]),
+      '#attributes' => array('class' => array('language-customization-checkbox')),
+      '#attached' => array(
+        'js' => array(drupal_get_path('module', 'language') . '/language.admin.js' => array('type' => 'file')),
+      ),
+    );
+  }
 
   $negotiation_info = $form['#language_negotiation_info'];
   $enabled_methods = variable_get("language_negotiation_$type", array());
@@ -519,12 +538,13 @@ function theme_language_negotiation_configure_form($variables) {
       'rows' => $rows,
       'attributes' => array('id' => "language-negotiation-methods-$type"),
     );
-    $table  = theme('table', $variables);
+    $table  = drupal_render($form[$type]['configurable']);
+    $table .= theme('table', $variables);
     $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-' . $type . '-wrapper">' . $title . $description . $table . '</div>';
   }
 
   $output .= drupal_render_children($form);
@@ -537,11 +557,16 @@ 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');
+
   foreach ($configurable_types as $type) {
     $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'])) {
+      $configurable[$type] = !empty($form_state['values'][$type]['configurable']);
+    }
 
     foreach ($method_weights_input as $method_id => $weight) {
       if ($enabled_methods[$method_id]) {
@@ -555,7 +580,15 @@ function language_negotiation_configure_form_submit($form, &$form_state) {
 
   // Update non-configurable language types and the related language negotiation
   // configuration.
-  language_types_set();
+  language_types_set($configurable);
+
+  // Clear the block's cache to change the block name when there is only one
+  // Invalidate the block cache to update custom block-based derivatives.
+  if (module_exists('block')) {
+    drupal_container()->get('plugin.manager.block')->clearCachedDefinitions();
+  }
+  // $block_manager = new BlockManager(array('Drupal\language\Plugin\Derivative\LanguageBlock'));
+  // $block_manager->clearCachedDefinitions();
 
   $form_state['redirect'] = 'admin/config/regional/language/detection';
   drupal_set_message(t('Language negotiation configuration saved.'));
diff --git a/core/modules/language/language.admin.js b/core/modules/language/language.admin.js
new file mode 100644
index 0000000..63b3acd
--- /dev/null
+++ b/core/modules/language/language.admin.js
@@ -0,0 +1,35 @@
+(function ($) {
+
+"use strict";
+
+/**
+ * Makes language negotiation inherit user interface negotiation.
+ */
+Drupal.behaviors.negotiationLanguage = {
+  attach: function (context) {
+    var $context = $(context);
+    // Given a customization checkbox derive the language type being changed.
+    var toggleTable = function ($checkbox) {
+      // Get the language detection type such as User interface text
+      // language detection or Content language detection.
+      var detectiontype = $checkbox.attr('name').replace('[configurable]', '');
+      var $table = $('.table-' + detectiontype + '-wrapper');
+      if ($checkbox.is(':checked')) {
+        $table.find('table, .tabledrag-toggle-weight-wrapper').show();
+      }
+      else {
+        $table.find('table, .tabledrag-toggle-weight-wrapper').hide();
+      }
+    };
+    // Bind hide/show + rearrange to customization checkboxes.
+    $('body').once('negotiation-language-admin-bind').on('click', '#language-negotiation-configure-form :input.language-customization-checkbox', function (e) {
+      toggleTable($(e.target));
+    });
+    // Initially, hide language detection types that are not customized.
+    $('#language-negotiation-configure-form :input.language-customization-checkbox:not(:checked)').each(function (index, element) {
+      toggleTable($(element));
+    });
+  }
+};
+
+})(jQuery);
diff --git a/core/modules/language/language.module b/core/modules/language/language.module
index 6bbb5a7..a4c2339 100644
--- a/core/modules/language/language.module
+++ b/core/modules/language/language.module
@@ -607,14 +607,16 @@ 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,
     ),
   );
 }
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 d451b27..d27ca3e 100644
--- a/core/modules/language/lib/Drupal/language/Plugin/Derivative/LanguageBlock.php
+++ b/core/modules/language/lib/Drupal/language/Plugin/Derivative/LanguageBlock.php
@@ -38,11 +38,17 @@ public function getDerivativeDefinition($derivative_id, array $base_plugin_defin
   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(FALSE);
+    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 $this->derivatives;
   }
 
diff --git a/core/modules/language/lib/Drupal/language/Tests/LanguageNegotiationInfoTest.php b/core/modules/language/lib/Drupal/language/Tests/LanguageNegotiationInfoTest.php
index 8aea763..e96a3d1 100644
--- a/core/modules/language/lib/Drupal/language/Tests/LanguageNegotiationInfoTest.php
+++ b/core/modules/language/lib/Drupal/language/Tests/LanguageNegotiationInfoTest.php
@@ -68,6 +68,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'));
 
@@ -157,8 +158,9 @@ protected function languageNegotiationUpdate($op = 'enable') {
    */
   protected function checkFixedLanguageTypes() {
     drupal_static_reset('language_types_info');
+    $configurable = config('system.language.types')->get('configurable');
     foreach (language_types_info() as $type => $info) {
-      if (isset($info['fixed'])) {
+      if (empty($configurable[$type]) && 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/lib/Drupal/language/Tests/LanguageUILanguageNegotiationTest.php b/core/modules/language/lib/Drupal/language/Tests/LanguageUILanguageNegotiationTest.php
index a6c1dc7..0c287e4 100644
--- a/core/modules/language/lib/Drupal/language/Tests/LanguageUILanguageNegotiationTest.php
+++ b/core/modules/language/lib/Drupal/language/Tests/LanguageUILanguageNegotiationTest.php
@@ -190,7 +190,7 @@ function testUILanguageNegotiation() {
       ),
       // Language prefix.
       array(
-        'language_negotiation' => array(LANGUAGE_NEGOTIATION_URL, LANGUAGE_NEGOTIATION_SELECTED),
+        'language_negotiation' => array(LANGUAGE_NEGOTIATION_URL, LANGUAGE_NEGOTIATION_BROWSER),
         'path' => "$langcode/admin/config",
         'expect' => $language_string,
         'expected_method_id' => LANGUAGE_NEGOTIATION_URL,
@@ -372,6 +372,15 @@ protected function runTest($test) {
     }
     $this->container->get('language_manager')->reset();
     $this->drupalGet($test['path'], array(), $test['http_header']);
+    // array(
+    //   'language_negotiation' => array(LANGUAGE_NEGOTIATION_URL, LANGUAGE_NEGOTIATION_SELECTED),
+    //   'path' => "$langcode/admin/config",
+    //   'expect' => $language_string,
+    //   'expected_method_id' => LANGUAGE_NEGOTIATION_URL,
+    //   'http_header' => $http_header_browser_fallback,
+    //   'message' => 'URL (PATH) > DEFAULT: with language prefix, UI language is switched based on path prefix',
+    // ),
+    
     $this->assertText($test['expect'], $test['message']);
     $this->assertText(t('Language negotiation method: @name', array('@name' => $test['expected_method_id'])));
   }
diff --git a/core/modules/language/tests/language_test/language_test.module b/core/modules/language/tests/language_test/language_test.module
index cb97937..0b98ed5 100644
--- a/core/modules/language/tests/language_test/language_test.module
+++ b/core/modules/language/tests/language_test/language_test.module
@@ -30,6 +30,7 @@ function language_test_language_types_info() {
       ),
       'fixed_test_language_type' => array(
         'fixed' => array('test_language_negotiation_method'),
+        'locked' => TRUE,
       ),
     );
   }
@@ -40,7 +41,7 @@ function language_test_language_types_info() {
  */
 function language_test_language_types_info_alter(array &$language_types) {
   if (state()->get('language_test.content_language_type')) {
-    unset($language_types[LANGUAGE_TYPE_CONTENT]['fixed']);
+    $language_types[LANGUAGE_TYPE_CONTENT]['locked'] = FALSE;
   }
 }
 
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..114fef6
--- /dev/null
+++ b/core/modules/system/config/system.language.types.yml
@@ -0,0 +1,5 @@
+# system.language.types.yml
+configurable:
+  language_interface: '1'
+  language_content: '0'
+  language_url: '0'
diff --git a/core/modules/translation_entity/translation_entity.module b/core/modules/translation_entity/translation_entity.module
index cb75cb2..52e0c2c 100644
--- a/core/modules/translation_entity/translation_entity.module
+++ b/core/modules/translation_entity/translation_entity.module
@@ -63,9 +63,9 @@ function translation_entity_module_implements_alter(&$implementations, $hook) {
  * Implements hook_language_type_info_alter().
  */
 function translation_entity_language_types_info_alter(array &$language_types) {
-  // Make content language negotiation configurable by removing its predefined
-  // configuration.
-  unset($language_types[LANGUAGE_TYPE_CONTENT]['fixed']);
+  // Make content language negotiation configurable by removing unsetting the
+  // 'locked' flag.
+  $language_types[LANGUAGE_TYPE_CONTENT]['locked'] = FALSE;
 }
 
 /**
