diff --git a/core/includes/update.inc b/core/includes/update.inc
index 30be3cd..f164fd6 100644
--- a/core/includes/update.inc
+++ b/core/includes/update.inc
@@ -207,8 +207,10 @@ function update_prepare_d8_language() {
     }
     variable_set('locale_translation_plurals', $plurals);
     variable_set('locale_translation_javascript', $javascript);
-    variable_set('locale_language_negotiation_url_prefixes', $prefixes);
-    variable_set('locale_language_negotiation_url_domains', $domains);
+    config('language.negotiation')
+      ->set('url.prefixes', $prefixes)
+      ->set('url.domains', $domains)
+      ->save();
 
     // Drop now unneeded columns.
     db_drop_field('languages', 'plurals');
diff --git a/core/modules/language/config/language.negotiation.yml b/core/modules/language/config/language.negotiation.yml
new file mode 100644
index 0000000..2289761
--- /dev/null
+++ b/core/modules/language/config/language.negotiation.yml
@@ -0,0 +1,9 @@
+# @todo Consider to split negotiation settings into language-specific objects.
+session:
+    parameter: language
+url:
+    determination_part: '0'
+    prefixes:
+      en: ''
+    domains:
+      en: ''
diff --git a/core/modules/language/language.admin.inc b/core/modules/language/language.admin.inc
index a601d00..358f581 100644
--- a/core/modules/language/language.admin.inc
+++ b/core/modules/language/language.admin.inc
@@ -650,6 +650,9 @@ function language_negotiation_configure_form_submit($form, &$form_state) {
 
 /**
  * Builds the URL language negotiation method configuration form.
+ *
+ * @see language_negotiation_configure_url_form_validate()
+ * @see language_negotiation_configure_url_form_submit()
  */
 function language_negotiation_configure_url_form($form, &$form_state) {
   global $base_url;
@@ -662,7 +665,7 @@ function language_negotiation_configure_url_form($form, &$form_state) {
       LANGUAGE_NEGOTIATION_URL_PREFIX => t('Path prefix'),
       LANGUAGE_NEGOTIATION_URL_DOMAIN => t('Domain'),
     ),
-    '#default_value' => variable_get('language_negotiation_url_part', LANGUAGE_NEGOTIATION_URL_PREFIX),
+    '#default_value' => config('language.negotiation')->get('url.determination_part'),
   );
 
   $form['prefix'] = array(
@@ -713,12 +716,7 @@ function language_negotiation_configure_url_form($form, &$form_state) {
 
   $form_state['redirect'] = 'admin/config/regional/language/detection';
 
-  $form['actions']['#type'] = 'actions';
-  $form['actions']['submit'] = array(
-    '#type' => 'submit',
-    '#value' => t('Save configuration'),
-  );
-  return $form;
+  return system_config_form($form, $form_state);
 }
 
 /**
@@ -782,31 +780,40 @@ function language_negotiation_configure_url_form_validate($form, &$form_state) {
 }
 
 /**
- * Saves the URL language negotiation method settings.
+ * Form submission handler for language_negotiation_configure_url_form().
  */
 function language_negotiation_configure_url_form_submit($form, &$form_state) {
   // Save selected format (prefix or domain).
-  variable_set('language_negotiation_url_part', $form_state['values']['language_negotiation_url_part']);
+  config('language.negotiation')->set('url.determination_part', $form_state['values']['language_negotiation_url_part'])->save();
 
   // Save new domain and prefix values.
   language_negotiation_url_prefixes_save($form_state['values']['prefix']);
   language_negotiation_url_domains_save($form_state['values']['domain']);
-
-  drupal_set_message(t('Configuration saved.'));
 }
 
 /**
  * Builds the session language negotiation method configuration form.
+ *
+ * @see language_negotiation_configure_session_form_submit()
  */
 function language_negotiation_configure_session_form($form, &$form_state) {
   $form['language_negotiation_session_param'] = array(
     '#title' => t('Request/session parameter'),
     '#type' => 'textfield',
-    '#default_value' => variable_get('language_negotiation_session_param', 'language'),
+    '#default_value' => config('language.negotiation')->get('session.parameter'),
     '#description' => t('Name of the request/session parameter used to determine the desired language.'),
   );
 
   $form_state['redirect'] = 'admin/config/regional/language/detection';
 
-  return system_settings_form($form);
+  return system_config_form($form, $form_state);
+}
+
+/**
+ * Form submission handler for language_negotiation_configure_session_form().
+ */
+function language_negotiation_configure_session_form_submit($form, &$form_state) {
+  config('language.negotiation')
+    ->set('session.parameter', $form_state['values']['language_negotiation_session_param'])
+    ->save();
 }
diff --git a/core/modules/language/language.install b/core/modules/language/language.install
index 37f41d6..c40bd6a 100644
--- a/core/modules/language/language.install
+++ b/core/modules/language/language.install
@@ -37,10 +37,6 @@ function language_uninstall() {
 
   // Clear variables.
   variable_del('language_types');
-  variable_del('language_negotiation_url_part');
-  variable_del('language_negotiation_url_prefixes');
-  variable_del('language_negotiation_url_domains');
-  variable_del('language_negotiation_session_param');
   variable_del('language_content_type_default');
   variable_del('language_content_type_negotiation');
 
@@ -49,6 +45,10 @@ function language_uninstall() {
     variable_del("language_negotiation_methods_weight_$type");
   }
 
+  config('language.negotiation')
+    ->delete('session.parameter')
+    ->delete('url.determination_part');
+
   // Re-initialize the language system so successive calls to t() and other
   // functions will not expect languages to be present.
   drupal_language_initialize();
diff --git a/core/modules/language/language.negotiation.inc b/core/modules/language/language.negotiation.inc
index 48a8083..eeebd0e 100644
--- a/core/modules/language/language.negotiation.inc
+++ b/core/modules/language/language.negotiation.inc
@@ -171,7 +171,7 @@ function language_from_user($languages) {
  *   A valid language code on success, FALSE otherwise.
  */
 function language_from_session($languages) {
-  $param = variable_get('language_negotiation_session_param', 'language');
+  $param = config('language.negotiation')->get('session.parameter');
 
   // Request parameter: we need to update the session parameter only if we have
   // an authenticated user.
@@ -210,7 +210,7 @@ function language_from_url($languages, $request) {
     return $language_url;
   }
 
-  switch (variable_get('language_negotiation_url_part', LANGUAGE_NEGOTIATION_URL_PREFIX)) {
+  switch (config('language.negotiation')->get('url.determination_part')) {
     case LANGUAGE_NEGOTIATION_URL_PREFIX:
 
       $current_path = $request->attributes->get('system_path');
@@ -293,7 +293,7 @@ function language_from_url($languages, $request) {
  */
 function language_url_fallback($language = NULL, $request = NULL, $language_type = LANGUAGE_TYPE_INTERFACE) {
   $default = language_default();
-  $prefix = (variable_get('language_negotiation_url_part', LANGUAGE_NEGOTIATION_URL_PREFIX) == LANGUAGE_NEGOTIATION_URL_PREFIX);
+  $prefix = (config('language.negotiation')->get('url.determination_part') == LANGUAGE_NEGOTIATION_URL_PREFIX);
 
   // If the default language is not configured to convey language information,
   // a missing URL language information indicates that URL language should be
@@ -334,7 +334,7 @@ function language_switcher_url($type, $path) {
  * Return the session language switcher block.
  */
 function language_switcher_session($type, $path) {
-  $param = variable_get('language_negotiation_session_param', 'language');
+  $param = config('language.negotiation')->get('session.parameter');
   $language_query = isset($_SESSION[$param]) ? $_SESSION[$param] : language($type)->langcode;
 
   $languages = language_list();
@@ -388,7 +388,7 @@ function language_url_rewrite_url(&$path, &$options) {
   }
 
   if (isset($options['language'])) {
-    switch (variable_get('language_negotiation_url_part', LANGUAGE_NEGOTIATION_URL_PREFIX)) {
+    switch (config('language.negotiation')->get('url.determination_part')) {
       case LANGUAGE_NEGOTIATION_URL_DOMAIN:
         $domains = language_negotiation_url_domains();
         if (is_object($options['language']) && !empty($domains[$options['language']->langcode])) {
@@ -431,28 +431,28 @@ function language_url_rewrite_url(&$path, &$options) {
  * Reads language prefixes and uses the langcode if no prefix is set.
  */
 function language_negotiation_url_prefixes() {
-  return variable_get('language_negotiation_url_prefixes', array());
+  return config('language.negotiation')->get('url.prefixes');
 }
 
 /**
  * Saves language prefix settings.
  */
 function language_negotiation_url_prefixes_save(array $prefixes) {
-  variable_set('language_negotiation_url_prefixes', $prefixes);
+  config('language.negotiation')->set('url.prefixes', $prefixes)->save();
 }
 
 /**
  * Reads language domains.
  */
 function language_negotiation_url_domains() {
-  return variable_get('language_negotiation_url_domains', array());
+  return config('language.negotiation')->get('url.domains');
 }
 
 /**
  * Saves the language domain settings.
  */
 function language_negotiation_url_domains_save(array $domains) {
-  variable_set('language_negotiation_url_domains', $domains);
+  config('language.negotiation')->set('url.domains', $domains)->save();
 }
 
 /**
@@ -467,7 +467,7 @@ function language_url_rewrite_session(&$path, &$options) {
     global $user;
     if (!$user->uid) {
       $languages = language_list();
-      $query_param = check_plain(variable_get('language_negotiation_session_param', 'language'));
+      $query_param = check_plain(config('language.negotiation')->get('session.parameter'));
       $query_value = isset($_GET[$query_param]) ? check_plain($_GET[$query_param]) : NULL;
       $query_rewrite = isset($languages[$query_value]) && language_negotiation_method_enabled(LANGUAGE_NEGOTIATION_SESSION);
     }
diff --git a/core/modules/language/lib/Drupal/language/Tests/LanguageUILanguageNegotiationTest.php b/core/modules/language/lib/Drupal/language/Tests/LanguageUILanguageNegotiationTest.php
index d12bdfa..db7fad7 100644
--- a/core/modules/language/lib/Drupal/language/Tests/LanguageUILanguageNegotiationTest.php
+++ b/core/modules/language/lib/Drupal/language/Tests/LanguageUILanguageNegotiationTest.php
@@ -238,7 +238,7 @@ class LanguageUILanguageNegotiationTest extends WebTestBase {
       language_negotiation_set(LANGUAGE_TYPE_INTERFACE, $method_weights);
     }
     if (!empty($test['language_negotiation_url_part'])) {
-      variable_set('language_negotiation_url_part', $test['language_negotiation_url_part']);
+      config('language.negotiation')->set('url.determination_part', $test['language_negotiation_url_part'])->save();
     }
     if (!empty($test['language_test_domain'])) {
       variable_set('language_test_domain', $test['language_test_domain']);
diff --git a/core/modules/language/lib/Drupal/language/Tests/LanguageUrlRewritingTest.php b/core/modules/language/lib/Drupal/language/Tests/LanguageUrlRewritingTest.php
index 72f2116..a5dad42 100644
--- a/core/modules/language/lib/Drupal/language/Tests/LanguageUrlRewritingTest.php
+++ b/core/modules/language/lib/Drupal/language/Tests/LanguageUrlRewritingTest.php
@@ -100,7 +100,7 @@ class LanguageUrlRewritingTest extends WebTestBase {
     $this->drupalPost('admin/config/regional/language/detection/url', $edit, t('Save configuration'));
 
     // Enable domain configuration.
-    variable_set('language_negotiation_url_part', LANGUAGE_NEGOTIATION_URL_DOMAIN);
+    config('language.negotiation')->set('url.determination_part', LANGUAGE_NEGOTIATION_URL_DOMAIN)->save();
 
     // Reset static caching.
     drupal_static_reset('language_list');
diff --git a/core/modules/locale/lib/Drupal/locale/Tests/LocaleUninstallTest.php b/core/modules/locale/lib/Drupal/locale/Tests/LocaleUninstallTest.php
index 00fb2b0..6059b99 100644
--- a/core/modules/locale/lib/Drupal/locale/Tests/LocaleUninstallTest.php
+++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleUninstallTest.php
@@ -48,6 +48,7 @@ class LocaleUninstallTest extends WebTestBase {
    */
   function testUninstallProcess() {
     $locale_module = array('locale', 'language');
+    $language_negotiation_config = config('language.negotiation');
 
     $language = (object) array(
       'langcode' => 'fr',
@@ -92,8 +93,10 @@ class LocaleUninstallTest extends WebTestBase {
     variable_set('language_negotiation_' . LANGUAGE_TYPE_URL, language_language_negotiation_info());
 
     // Change language negotiation settings.
-    variable_set('language_negotiation_url_part', LANGUAGE_NEGOTIATION_URL_PREFIX);
-    variable_set('language_negotiation_session_param', TRUE);
+    $language_negotiation_config
+      ->set('url.determination_part', LANGUAGE_NEGOTIATION_URL_PREFIX)
+      ->set('session.parameter', TRUE)
+      ->save();
 
     // Uninstall Locale.
     module_disable($locale_module);
@@ -125,8 +128,8 @@ class LocaleUninstallTest extends WebTestBase {
     $this->assertTrue($language_negotiation, t('URL language negotiation: %setting', array('%setting' => t($language_negotiation ? 'none' : 'set'))));
 
     // Check language negotiation method settings.
-    $this->assertFalse(variable_get('language_negotiation_url_part', FALSE), t('URL language negotiation method indicator settings cleared.'));
-    $this->assertFalse(variable_get('language_negotiation_session_param', FALSE), t('Visit language negotiation method settings cleared.'));
+    $this->assertNull($language_negotiation_config->get('url.determination_part'), t('URL language negotiation method indicator settings cleared.'));
+    $this->assertNull($language_negotiation_config->get('session.parameter'), t('Visit language negotiation method settings cleared.'));
 
     // Check JavaScript parsed.
     $javascript_parsed_count = count(variable_get('javascript_parsed', array()));
diff --git a/core/modules/locale/locale.install b/core/modules/locale/locale.install
index 334b401..10ca3b7 100644
--- a/core/modules/locale/locale.install
+++ b/core/modules/locale/locale.install
@@ -554,20 +554,12 @@ function locale_update_8007() {
  * @ingroup config_upgrade
  */
 function locale_update_8008() {
-  $variable_name_map = array(
-    'locale_language_negotiation_url_part' => 'language_negotiation_url_part',
-    'locale_language_negotiation_url_domains' => 'language_negotiation_url_domains',
-    'locale_language_negotiation_url_prefixes' => 'language_negotiation_url_prefixes',
-    'locale_language_negotiation_session_param' => 'language_negotiation_session_param',
-  );
-  foreach ($variable_name_map as $deprecated_variable_name => $new_variable_name) {
-    // Check if this variable is stored in the db and if so rename it.
-    $value = update_variable_get($deprecated_variable_name);
-    if ($value !== NULL) {
-      update_variable_set($new_variable_name, $value);
-      update_variable_del($deprecated_variable_name);
-    }
-  }
+  update_variables_to_config('language.negotiation', array(
+    'locale_language_negotiation_session_param' => 'session.parameter',
+    'language_negotiation_url_part' => 'url.determination_part',
+    'language_negotiation_url_prefixes' => 'url.prefixes',
+    'language_negotiation_url_domains' => 'url.domains',
+  ));
 }
 
 /**
diff --git a/core/modules/overlay/overlay.module b/core/modules/overlay/overlay.module
index acfcc2c..dc926ec 100644
--- a/core/modules/overlay/overlay.module
+++ b/core/modules/overlay/overlay.module
@@ -667,7 +667,7 @@ function overlay_overlay_parent_initialize() {
   $path_prefixes = array();
   if (module_exists('language')) {
     language_negotiation_include();
-    if (variable_get('language_negotiation_url_part', LANGUAGE_NEGOTIATION_URL_PREFIX) == LANGUAGE_NEGOTIATION_URL_PREFIX) {
+    if (config('language.negotiation')->get('url.determination_part') == LANGUAGE_NEGOTIATION_URL_PREFIX) {
       // Skip the empty string indicating the default language. We always accept
       // paths without a prefix.
       $path_prefixes = language_negotiation_url_prefixes();
