diff --git a/core/includes/locale.inc b/core/includes/locale.inc
index 8a381ed..43bac8d 100644
--- a/core/includes/locale.inc
+++ b/core/includes/locale.inc
@@ -215,7 +215,7 @@ function locale_language_from_user($languages) {
   global $user;
 
   if ($user->uid) {
-    return $user->language;
+    return $user->preferred_langcode;
   }
 
   // No language preference from the user.
diff --git a/core/modules/locale/locale.module b/core/modules/locale/locale.module
index 4a786be..5c2a576 100644
--- a/core/modules/locale/locale.module
+++ b/core/modules/locale/locale.module
@@ -236,12 +236,12 @@ function locale_language_selector_form($user) {
     '#title' => t('Language settings'),
     '#weight' => 1,
   );
-  $form['locale']['language'] = array(
+  $form['locale']['preferred_langcode'] = array(
     '#type' => (count($names) <= 5 ? 'radios' : 'select'),
     '#title' => t('Language'),
     '#default_value' => $user_preferred_language->langcode,
     '#options' => $names,
-    '#description' => $mode ? t("This account's default language for e-mails, and preferred language for site presentation.") : t("This account's default language for e-mails."),
+    '#description' => $mode ? t("This account's preferred language for e-mails and site presentation.") : t("This account's preferred language for e-mails."),
   );
   return $form;
 }
diff --git a/core/modules/locale/locale.test b/core/modules/locale/locale.test
index 208c5e6..ef473c2 100644
--- a/core/modules/locale/locale.test
+++ b/core/modules/locale/locale.test
@@ -1644,13 +1644,13 @@ class LocaleUserLanguageFunctionalTest extends DrupalWebTestCase {
     $this->assertNoText($name_disabled, t('Disabled language not present on form.'));
     // Switch to our custom language.
     $edit = array(
-      'language' => $langcode,
+      'preferred_langcode' => $langcode,
     );
     $this->drupalPost($path, $edit, t('Save'));
     // Ensure form was submitted successfully.
     $this->assertText(t('The changes have been saved.'), t('Changes were saved.'));
     // Check if language was changed.
-    $elements = $this->xpath('//input[@id=:id]', array(':id' => 'edit-language-' . $langcode));
+    $elements = $this->xpath('//input[@id=:id]', array(':id' => 'edit-preferred-langcode-' . $langcode));
     $this->assertTrue(isset($elements[0]) && !empty($elements[0]['checked']), t('Default language successfully updated.'));
 
     $this->drupalLogout();
@@ -1702,7 +1702,7 @@ class LocaleUserCreationTest extends DrupalWebTestCase {
     // Check if the language selector is available on admin/people/create and
     // set to the currently active language.
     $this->drupalGet($langcode . '/admin/people/create');
-    $this->assertFieldChecked("edit-language-$langcode", t('Global language set in the language selector.'));
+    $this->assertFieldChecked("edit-preferred-langcode-$langcode", t('Global language set in the language selector.'));
 
     // Create a user with the admin/people/create form and check if the correct
     // language is set.
@@ -1717,7 +1717,7 @@ class LocaleUserCreationTest extends DrupalWebTestCase {
     $this->drupalPost($langcode . '/admin/people/create', $edit, t('Create new account'));
 
     $user = user_load_by_name($username);
-    $this->assertEqual($user->language, $langcode, t('New user has correct language set.'));
+    $this->assertEqual($user->preferred_langcode, $langcode, t('New user has correct language set.'));
 
     // Register a new user and check if the language selector is hidden.
     $this->drupalLogout();
@@ -1734,7 +1734,7 @@ class LocaleUserCreationTest extends DrupalWebTestCase {
     $this->drupalPost($langcode . '/user/register', $edit, t('Create new account'));
 
     $user = user_load_by_name($username);
-    $this->assertEqual($user->language, $langcode, t('New user has correct language set.'));
+    $this->assertEqual($user->preferred_langcode, $langcode, t('New user has correct language set.'));
 
     // Test if the admin can use the language selector and if the
     // correct language is was saved.
@@ -1742,7 +1742,7 @@ class LocaleUserCreationTest extends DrupalWebTestCase {
 
     $this->drupalLogin($admin_user);
     $this->drupalGet($user_edit);
-    $this->assertFieldChecked("edit-language-$langcode", t('Language selector is accessible and correct language is selected.'));
+    $this->assertFieldChecked("edit-preferred-langcode-$langcode", t('Language selector is accessible and correct language is selected.'));
 
     // Set pass_raw so we can login the new user.
     $user->pass_raw = $this->randomName(10);
@@ -1755,7 +1755,7 @@ class LocaleUserCreationTest extends DrupalWebTestCase {
 
     $this->drupalLogin($user);
     $this->drupalGet($user_edit);
-    $this->assertFieldChecked("edit-language-$langcode", t('Language selector is accessible and correct language is selected.'));
+    $this->assertFieldChecked("edit-preferred-langcode-$langcode", t('Language selector is accessible and correct language is selected.'));
   }
 }
 
@@ -2682,7 +2682,7 @@ class LocaleCommentLanguageFunctionalTest extends DrupalWebTestCase {
 
     // Change user language preference, this way interface language is always
     // French no matter what path prefix the URLs have.
-    $edit = array('language' => 'fr');
+    $edit = array('preferred_langcode' => 'fr');
     $this->drupalPost("user/{$admin_user->uid}/edit", $edit, t('Save'));
   }
 
diff --git a/core/modules/openid/openid.module b/core/modules/openid/openid.module
index edd73d3..2e0fdce 100644
--- a/core/modules/openid/openid.module
+++ b/core/modules/openid/openid.module
@@ -263,8 +263,8 @@ function openid_form_user_register_form_alter(&$form, &$form_state) {
       // specific) strings.
       foreach (array_reverse($candidate_languages) as $candidate_language) {
         if (isset($enabled_languages[$candidate_language])) {
-          $form['locale']['language']['#type'] = 'hidden';
-          $form['locale']['language']['#value'] = $candidate_language;
+          $form['locale']['preferred_langcode']['#type'] = 'hidden';
+          $form['locale']['preferred_langcode']['#value'] = $candidate_language;
         }
       }
     }
diff --git a/core/modules/openid/openid.test b/core/modules/openid/openid.test
index 5c6ca69..a08c918 100644
--- a/core/modules/openid/openid.test
+++ b/core/modules/openid/openid.test
@@ -421,7 +421,7 @@ class OpenIDRegistrationTestCase extends OpenIDWebTestCase {
     $this->assertTrue($user, t('User was registered with right username.'));
     $this->assertEqual($user->mail, 'john@example.com', t('User was registered with right email address.'));
     $this->assertEqual($user->timezone, 'Europe/London', t('User was registered with right timezone.'));
-    $this->assertEqual($user->language, 'en', t('User was registered with right language.'));
+    $this->assertEqual($user->preferred_langcode, 'en', t('User was registered with right language.'));
     $this->assertFalse($user->data, t('No additional user info was saved.'));
 
     $this->submitLoginForm($identity);
@@ -463,7 +463,7 @@ class OpenIDRegistrationTestCase extends OpenIDWebTestCase {
     $this->assertTrue($user, t('User was registered with right username.'));
     $this->assertEqual($user->mail, 'john@example.com', t('User was registered with right email address.'));
     $this->assertEqual($user->timezone, 'Europe/London', t('User was registered with right timezone.'));
-    $this->assertEqual($user->language, 'en', t('User was registered with right language.'));
+    $this->assertEqual($user->preferred_langcode, 'en', t('User was registered with right language.'));
     $this->assertFalse($user->data, t('No additional user info was saved.'));
 
     $this->drupalLogout();
@@ -508,7 +508,7 @@ class OpenIDRegistrationTestCase extends OpenIDWebTestCase {
 
     $user = user_load_by_name('john');
     $this->assertTrue($user, t('User was registered with right username.'));
-    $this->assertFalse($user->language, t('No user language was saved.'));
+    $this->assertFalse($user->preferred_langcode, t('No user language was saved.'));
     $this->assertFalse($user->data, t('No additional user info was saved.'));
 
     // Follow the one-time login that was sent in the welcome e-mail.
@@ -548,7 +548,7 @@ class OpenIDRegistrationTestCase extends OpenIDWebTestCase {
 
     $user = user_load_by_name('john');
     $this->assertTrue($user, t('User was registered with right username.'));
-    $this->assertFalse($user->language, t('No user language was saved.'));
+    $this->assertFalse($user->preferred_langcode, t('No user language was saved.'));
     $this->assertFalse($user->data, t('No additional user info was saved.'));
 
     // Follow the one-time login that was sent in the welcome e-mail.
@@ -593,7 +593,7 @@ class OpenIDRegistrationTestCase extends OpenIDWebTestCase {
     $this->assertTrue($user, t('User was registered with right username.'));
     $this->assertEqual($user->mail, 'john@example.com', t('User was registered with right email address.'));
     $this->assertEqual($user->timezone, 'Europe/London', t('User was registered with right timezone.'));
-    $this->assertEqual($user->language, 'en', t('User was registered with right language.'));
+    $this->assertEqual($user->preferred_langcode, 'en', t('User was registered with right language.'));
   }
 }
 
diff --git a/core/modules/path/path.test b/core/modules/path/path.test
index 3072150..9ee8a23 100644
--- a/core/modules/path/path.test
+++ b/core/modules/path/path.test
@@ -317,7 +317,7 @@ class PathLanguageTestCase extends DrupalWebTestCase {
     $this->drupalPost('admin/config/regional/language/detection', $edit, t('Save settings'));
 
     // Change user language preference.
-    $edit = array('language' => 'fr');
+    $edit = array('preferred_langcode' => 'fr');
     $this->drupalPost("user/{$this->web_user->uid}/edit", $edit, t('Save'));
 
     // Check that the English alias works. In this situation French is the
diff --git a/core/modules/simpletest/tests/common.test b/core/modules/simpletest/tests/common.test
index fee3831..85d94e9 100644
--- a/core/modules/simpletest/tests/common.test
+++ b/core/modules/simpletest/tests/common.test
@@ -2394,7 +2394,7 @@ class CommonFormatDateTestCase extends DrupalWebTestCase {
     // Create a test user to carry out the tests.
     $test_user = $this->drupalCreateUser();
     $this->drupalLogin($test_user);
-    $edit = array('language' => self::LANGCODE, 'mail' => $test_user->mail, 'timezone' => 'America/Los_Angeles');
+    $edit = array('preferred_langcode' => self::LANGCODE, 'mail' => $test_user->mail, 'timezone' => 'America/Los_Angeles');
     $this->drupalPost('user/' . $test_user->uid . '/edit', $edit, t('Save'));
 
     // Disable session saving as we are about to modify the global $user.
@@ -2403,7 +2403,7 @@ class CommonFormatDateTestCase extends DrupalWebTestCase {
     $real_user = $user;
     $user = user_load($test_user->uid, TRUE);
     $real_language = $language_interface->langcode;
-    $language_interface->langcode = $user->language;
+    $language_interface->langcode = $user->preferred_langcode;
     // Simulate a Drupal bootstrap with the logged-in user.
     date_default_timezone_set(drupal_get_user_timezone());
 
diff --git a/core/modules/simpletest/tests/upgrade/upgrade.language.test b/core/modules/simpletest/tests/upgrade/upgrade.language.test
index b132e10..d6a6ec8 100644
--- a/core/modules/simpletest/tests/upgrade/upgrade.language.test
+++ b/core/modules/simpletest/tests/upgrade/upgrade.language.test
@@ -78,4 +78,16 @@ class LanguageUpgradePathTestCase extends UpgradePathTestCase {
     $this->drupalGet('node/add/page');
     $this->assertNoFieldByName('langcode');
   }
+
+  /**
+   * Tests a successfull user upgrade.
+   */
+  public function testLanguageUserUpgrade() {
+    db_update('users')->fields(array('language' => 'ca'))->condition('uid', '1')->execute();
+    $this->assertTrue($this->performUpgrade(), t('The upgrade was completed successfully.'));
+
+    // Directly check the user language property.
+    $user = db_query('SELECT * FROM {users} WHERE uid = :uid', array(':uid' => 1))->fetchObject();
+    $this->assertTrue($user->preferred_langcode == 'ca', t('User language code found.'));
+  }
 }
diff --git a/core/modules/user/user.install b/core/modules/user/user.install
index f7175c3..4f6c76d 100644
--- a/core/modules/user/user.install
+++ b/core/modules/user/user.install
@@ -137,6 +137,13 @@ function user_schema() {
         'default' => '',
         'description' => 'Unique user name.',
       ),
+      'langcode' => array(
+        'type' => 'varchar',
+        'length' => 12,
+        'not null' => TRUE,
+        'default' => '',
+        'description' => "The default {language}.langcode of the user's profile data.",
+      ),
       'pass' => array(
         'type' => 'varchar',
         'length' => 128,
@@ -202,12 +209,12 @@ function user_schema() {
         'not null' => FALSE,
         'description' => "User's time zone.",
       ),
-      'language' => array(
+      'preferred_langcode' => array(
         'type' => 'varchar',
         'length' => 12,
         'not null' => TRUE,
         'default' => '',
-        'description' => "User's default language.",
+        'description' => 'The {language}.langcode that the user prefers for receiving emails and viewing the site.',
       ),
       'picture' => array(
         'type' => 'int',
@@ -354,5 +361,31 @@ function user_update_8000() {
 }
 
 /**
+ * Rename users.language field to users.preferred_langcode and add a users.langcode field.
+ *
+ * @see http://drupal.org/node/1439680
+ */
+function user_update_8001() {
+  $preferred_langcode_field = array(
+    'type' => 'varchar',
+    'length' => 12,
+    'not null' => TRUE,
+    'default' => '',
+    'description' => 'The {language}.langcode that the user prefers for receiving emails and viewing the site.',
+  );
+  db_change_field('users', 'language', 'preferred_langcode', $preferred_langcode_field);
+
+  $langcode_field = array(
+    'type' => 'varchar',
+    'length' => 12,
+    'not null' => TRUE,
+    'default' => '',
+    'description' => "The default {language}.langcode of the user's profile data.",
+    'initial' => LANGUAGE_NONE,
+  );
+  db_add_field('users', 'langcode', $langcode_field);
+}
+
+/**
  * @} End of "addtogroup updates-7.x-to-8.x"
  */
diff --git a/core/modules/user/user.module b/core/modules/user/user.module
index f4479ec..63c26d7 100644
--- a/core/modules/user/user.module
+++ b/core/modules/user/user.module
@@ -423,6 +423,9 @@ function user_save($account, $edit = array()) {
     foreach ($edit as $key => $value) {
       $account->$key = $value;
     }
+    if (empty($account->langcode)) {
+      $account->langcode = LANGUAGE_NONE;
+    }
     field_attach_presave('user', $account);
     module_invoke_all('entity_presave', $account, 'user');
 
@@ -3460,8 +3463,8 @@ function theme_user_signature($variables) {
  */
 function user_preferred_language($account, $default = NULL) {
   $language_list = language_list();
-  if (!empty($account->language) && isset($language_list[$account->language])) {
-    return $language_list[$account->language];
+  if (!empty($account->preferred_langcode) && isset($language_list[$account->preferred_langcode])) {
+    return $language_list[$account->preferred_langcode];
   }
   else {
     return $default ? $default : language_default();
diff --git a/core/modules/user/user.test b/core/modules/user/user.test
index 0c5f90f..35451d1 100644
--- a/core/modules/user/user.test
+++ b/core/modules/user/user.test
@@ -166,7 +166,7 @@ class UserRegistrationTestCase extends DrupalWebTestCase {
     $this->assertTrue(($new_user->created > REQUEST_TIME - 20 ), t('Correct creation time.'));
     $this->assertEqual($new_user->status, variable_get('user_register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL) == USER_REGISTER_VISITORS ? 1 : 0, t('Correct status field.'));
     $this->assertEqual($new_user->timezone, variable_get('date_default_timezone'), t('Correct time zone field.'));
-    $this->assertEqual($new_user->language, '', t('Correct language field.'));
+    $this->assertEqual($new_user->preferred_langcode, '', t('Correct language field.'));
     $this->assertEqual($new_user->picture, '', t('Correct picture field.'));
     $this->assertEqual($new_user->init, $mail, t('Correct init field.'));
   }
diff --git a/core/modules/user/user.tokens.inc b/core/modules/user/user.tokens.inc
index 76ec4a2..833e763 100644
--- a/core/modules/user/user.tokens.inc
+++ b/core/modules/user/user.tokens.inc
@@ -65,10 +65,10 @@ function user_tokens($type, $tokens, array $data = array(), array $options = arr
   $url_options = array('absolute' => TRUE);
   if (isset($options['language'])) {
     $url_options['language'] = $options['language'];
-    $language_code = $options['language']->langcode;
+    $langcode = $options['language']->langcode;
   }
   else {
-    $language_code = NULL;
+    $langcode = NULL;
   }
   $sanitize = !empty($options['sanitize']);
 
@@ -103,12 +103,12 @@ function user_tokens($type, $tokens, array $data = array(), array $options = arr
 
         // These tokens are default variations on the chained tokens handled below.
         case 'last-login':
-          $replacements[$original] = !empty($account->login) ? format_date($account->login, 'medium', '', NULL, $language_code) : t('never');
+          $replacements[$original] = !empty($account->login) ? format_date($account->login, 'medium', '', NULL, $langcode) : t('never');
           break;
 
         case 'created':
           // In the case of user_presave the created date may not yet be set.
-          $replacements[$original] = !empty($account->created) ? format_date($account->created, 'medium', '', NULL, $language_code) : t('not yet created');
+          $replacements[$original] = !empty($account->created) ? format_date($account->created, 'medium', '', NULL, $langcode) : t('not yet created');
           break;
       }
     }
