diff --git a/core/modules/entity/entity.module b/core/modules/entity/entity.module
index 2c54daa..8bd2fc1 100644
--- a/core/modules/entity/entity.module
+++ b/core/modules/entity/entity.module
@@ -467,12 +467,13 @@ function entity_form_id(EntityInterface $entity, $operation = 'default') {
  * @return
  *   A $form_state array already filled the entity form controller.
  */
-function entity_form_state_defaults(EntityInterface $entity, $operation = 'default') {
+function entity_form_state_defaults(EntityInterface $entity, $operation = 'default', $langcode = NULL) {
   $form_state = array();
   $controller = entity_form_controller($entity->entityType(), $operation);
   $form_state['build_info']['callback'] = array($controller, 'build');
   $form_state['build_info']['base_form_id'] = $entity->entityType() . '_form';
   $form_state['build_info']['args'] = array($entity);
+  $form_state['langcode'] = $langcode;
   return $form_state;
 }
 
@@ -506,8 +507,8 @@ function entity_form_submit(EntityInterface $entity, $operation = 'default', &$f
  * @return
  *   The processed form for the given entity and operation.
  */
-function entity_get_form(EntityInterface $entity, $operation = 'default') {
-  $form_state = entity_form_state_defaults($entity, $operation);
+function entity_get_form(EntityInterface $entity, $operation = 'default', $langcode = NULL) {
+  $form_state = entity_form_state_defaults($entity, $operation, $langcode);
   $form_id = entity_form_id($entity, $operation);
   return drupal_build_form($form_id, $form_state);
 }
diff --git a/core/modules/entity/lib/Drupal/entity/Entity.php b/core/modules/entity/lib/Drupal/entity/Entity.php
index 9701d28..e63185d 100644
--- a/core/modules/entity/lib/Drupal/entity/Entity.php
+++ b/core/modules/entity/lib/Drupal/entity/Entity.php
@@ -8,6 +8,7 @@
 namespace Drupal\entity;
 
 use Drupal\Component\Uuid\Uuid;
+use Drupal\Core\Language\Language;
 
 /**
  * Defines a base entity class.
@@ -148,9 +149,7 @@ class Entity implements EntityInterface {
    * Implements EntityInterface::language().
    */
   public function language() {
-    // @todo: Check for language.module instead, once Field API language
-    // handling depends upon it too.
-    return module_exists('locale') ? language_load($this->langcode) : FALSE;
+    return !empty($this->langcode) ? language_load($this->langcode) : new Language(array('langcode' => LANGUAGE_NOT_SPECIFIED));
   }
 
   /**
diff --git a/core/modules/entity/lib/Drupal/entity/EntityFormController.php b/core/modules/entity/lib/Drupal/entity/EntityFormController.php
index 4f1263c..dabb330 100644
--- a/core/modules/entity/lib/Drupal/entity/EntityFormController.php
+++ b/core/modules/entity/lib/Drupal/entity/EntityFormController.php
@@ -207,12 +207,27 @@ class EntityFormController implements EntityFormControllerInterface {
   /**
    * Implements Drupal\entity\EntityFormControllerInterface::getFormLangcode().
    */
-  public function getFormLangcode($form_state) {
-    // @todo Introduce a new form language type (see hook_language_types_info())
-    // to be used as the default active form language, should it be missing, so
-    // that entity forms can be used to submit multilingual values.
-    $language = $this->getEntity($form_state)->language();
-    return !empty($language->langcode) ? $language->langcode : NULL;
+  public function getFormLangcode(array $form_state) {
+    $entity = $this->getEntity($form_state);
+    $translations = $entity->translations();
+
+    if (!empty($form_state['langcode'])) {
+      $langcode = $form_state['langcode'];
+    }
+    else {
+      // If no form langcode was provided we default to the current content
+      // language and inspect existing translations to find a valid fallback,
+      // if any.
+      $langcode = language(LANGUAGE_TYPE_CONTENT)->langcode;
+      $fallback = language_multilingual() ? language_fallback_get_candidates() : array();
+      while (!empty($langcode) && !isset($translations[$langcode])) {
+        $langcode = array_shift($fallback);
+      }
+    }
+
+    // If the site is not multilingual or no translation for the given form
+    // language is available, fall back to the entity language.
+    return !empty($langcode) ? $langcode : $entity->language()->langcode;
   }
 
   /**
diff --git a/core/modules/entity/lib/Drupal/entity/EntityFormControllerInterface.php b/core/modules/entity/lib/Drupal/entity/EntityFormControllerInterface.php
index 6765d85..95fb2fc 100644
--- a/core/modules/entity/lib/Drupal/entity/EntityFormControllerInterface.php
+++ b/core/modules/entity/lib/Drupal/entity/EntityFormControllerInterface.php
@@ -49,7 +49,7 @@ interface EntityFormControllerInterface {
    * @return string
    *   The form language code.
    */
-  public function getFormLangcode($form_state);
+  public function getFormLangcode(array $form_state);
 
   /**
    * Returns the operation identifying the form controller.
diff --git a/core/modules/entity/lib/Drupal/entity/Tests/EntityTranslationFormTest.php b/core/modules/entity/lib/Drupal/entity/Tests/EntityTranslationFormTest.php
new file mode 100644
index 0000000..3908184
--- /dev/null
+++ b/core/modules/entity/lib/Drupal/entity/Tests/EntityTranslationFormTest.php
@@ -0,0 +1,122 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\entity\Tests\EntityTranslationFormTest.
+ */
+
+namespace Drupal\entity\Tests;
+
+use Exception;
+use InvalidArgumentException;
+use Drupal\simpletest\WebTestBase;
+use Drupal\Core\Language\Language;
+
+/**
+ * Tests entity translation form.
+ */
+class EntityTranslationFormTest extends WebTestBase {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = array('entity_test', 'locale', 'node');
+
+  protected $langcodes;
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Entity translation form',
+      'description' => 'Tests entity translation form functionality.',
+      'group' => 'Entity API',
+    );
+  }
+
+  function setUp() {
+    parent::setUp();
+    // Enable translations for the test entity type.
+    variable_set('entity_test_translation', TRUE);
+
+    // Create test languages.
+    $this->langcodes = array();
+    for ($i = 0; $i < 2; ++$i) {
+      $language = new Language(array(
+        'langcode' => 'l' . $i,
+        'name' => $this->randomString(),
+      ));
+      $this->langcodes[$i] = $language->langcode;
+      language_save($language);
+    }
+  }
+
+  /**
+   * Tests entity form language.
+   */
+  function testEntityFormLanguage() {
+    $this->drupalCreateContentType(array('type' => 'page', 'name' => 'Basic page'));
+
+    $web_user = $this->drupalCreateUser(array('create page content', 'edit own page content', 'administer content types'));
+    $this->drupalLogin($web_user);
+
+    // Create a node with language LANGUAGE_NOT_SPECIFIED.
+    $edit = array();
+    $langcode = LANGUAGE_NOT_SPECIFIED;
+    $edit["title"] = $this->randomName(8);
+    $edit["body[$langcode][0][value]"] = $this->randomName(16);
+
+    $this->drupalGet('node/add/page');
+    $form_langcode = variable_get('entity_form_langcode', FALSE);
+    $this->drupalPost(NULL, $edit, t('Save'));
+
+    $node = $this->drupalGetNodeByTitle($edit["title"]);
+    $this->assertTrue($node->langcode == $form_langcode, 'Form language is the same as the entity language.');
+
+    // Edit the node and test the form language.
+    $this->drupalGet($this->langcodes[0] . '/node/' . $node->nid . '/edit');
+    $form_langcode = variable_get('entity_form_langcode', FALSE);
+    $this->assertTrue($node->langcode == $form_langcode, 'Form language is the same as the entity language.');
+
+    // Explicitly set form langcode.
+    $langcode = $this->langcodes[0];
+    entity_get_form($node, 'default', $langcode);
+    $form_langcode = variable_get('entity_form_langcode', FALSE);
+    $this->assertTrue($langcode == $form_langcode, 'Form language is the same as the language parameter.');
+
+    // Enable language selector.
+    $this->drupalGet('admin/structure/types/manage/page');
+    $edit = array('node_type_language_hidden' => FALSE, 'node_type_language_default' => LANGUAGE_NOT_SPECIFIED);
+    $this->drupalPost('admin/structure/types/manage/page', $edit, t('Save content type'));
+    $this->assertRaw(t('The content type %type has been updated.', array('%type' => 'Basic page')), t('Basic page content type has been updated.'));
+
+    // Create a node with language.
+    $edit = array();
+    $langcode = $this->langcodes[0];
+    $field_langcode = LANGUAGE_NOT_SPECIFIED;
+    $edit["title"] = $this->randomName(8);
+    $edit["body[$field_langcode][0][value]"] = $this->randomName(16);
+    $edit['langcode'] = $langcode;
+    $this->drupalPost('node/add/page', $edit, t('Save'));
+    $this->assertRaw(t('Basic page %title has been created.', array('%title' => $edit["title"])), t('Basic page created.'));
+
+    // Check to make sure the node was created.
+    $node = $this->drupalGetNodeByTitle($edit["title"]);
+    $this->assertTrue($node, t('Node found in database.'));
+
+    // Make body translatable.
+    $field = field_info_field('body');
+    $field['translatable'] = TRUE;
+    field_update_field($field);
+    $field = field_info_field('body');
+    $this->assertTrue($field['translatable'], "Field body is translatable.");
+
+    // Create a body translation and check the form language.
+    $langcode2 = $this->langcodes[1];
+    $node->set('body', array(array('value' => $this->randomName(16))), $langcode2);
+    $node->save();
+    $this->drupalGet($langcode2 . '/node/' . $node->nid . '/edit');
+    $form_langcode = variable_get('entity_form_langcode', FALSE);
+    $this->assertTrue($langcode2 == $form_langcode, "Node edit form language is $langcode2.");
+  }
+}
diff --git a/core/modules/entity/lib/Drupal/entity/Tests/EntityTranslationTest.php b/core/modules/entity/lib/Drupal/entity/Tests/EntityTranslationTest.php
index 252e048..40a4d87 100644
--- a/core/modules/entity/lib/Drupal/entity/Tests/EntityTranslationTest.php
+++ b/core/modules/entity/lib/Drupal/entity/Tests/EntityTranslationTest.php
@@ -22,7 +22,7 @@ class EntityTranslationTest extends WebTestBase {
    *
    * @var array
    */
-  public static $modules = array('entity_test', 'locale');
+  public static $modules = array('entity_test', 'locale', 'node');
 
   protected $langcodes;
 
@@ -231,4 +231,5 @@ class EntityTranslationTest extends WebTestBase {
     $entities = entity_load_multiple_by_properties('entity_test', array('uid' => $properties[$langcode]['uid'], 'default_langcode' => NULL));
     $this->assertEqual(count($entities), 2, 'Two entities loaded by uid without caring about property translatability.');
   }
+
 }
diff --git a/core/modules/entity/tests/modules/entity_test/entity_test.module b/core/modules/entity/tests/modules/entity_test/entity_test.module
index 02ec108..9b1b224 100644
--- a/core/modules/entity/tests/modules/entity_test/entity_test.module
+++ b/core/modules/entity/tests/modules/entity_test/entity_test.module
@@ -66,3 +66,11 @@ function entity_test_load_multiple(array $ids = NULL, $reset = FALSE) {
 function entity_test_delete_multiple(array $ids) {
   entity_get_controller('entity_test')->delete($ids);
 }
+
+/**
+ * Implements hook_form_BASE_FORM_ID_alter().
+ */
+function entity_test_form_node_form_alter(&$form, &$form_state, $form_id) {
+  $langcode = $form_state['controller']->getFormLangcode($form_state);
+  variable_set('entity_form_langcode', $langcode);
+}
diff --git a/core/modules/node/lib/Drupal/node/NodeFormController.php b/core/modules/node/lib/Drupal/node/NodeFormController.php
index b99547e..b27e1a6 100644
--- a/core/modules/node/lib/Drupal/node/NodeFormController.php
+++ b/core/modules/node/lib/Drupal/node/NodeFormController.php
@@ -337,7 +337,14 @@ class NodeFormController extends EntityFormController {
   protected function submitNodeLanguage(array $form, array &$form_state) {
     if (field_has_translation_handler('node', 'node')) {
       $bundle = $form_state['values']['type'];
-      $node_language = $form_state['values']['langcode'];
+      $entity = $this->getEntity($form_state);
+      $form_langcode = $this->getFormLangcode($form_state);
+
+      // If we are editing the default language values, we use the submitted
+      // entity language as the new language for fields to handle any language
+      // change. Otherwise the current form language is the proper value, since
+      // in this case it is not supposed to change.
+      $current_langcode = $entity->language()->langcode == $form_langcode ? $form_state['values']['langcode'] : $form_langcode;
 
       foreach (field_info_instances('node', $bundle) as $instance) {
         $field_name = $instance['field_name'];
@@ -346,8 +353,8 @@ class NodeFormController extends EntityFormController {
 
         // Handle a possible language change: new language values are inserted,
         // previous ones are deleted.
-        if ($field['translatable'] && $previous_langcode != $node_language) {
-          $form_state['values'][$field_name][$node_language] = $form_state['values'][$field_name][$previous_langcode];
+        if ($field['translatable'] && $previous_langcode != $current_langcode) {
+          $form_state['values'][$field_name][$current_langcode] = $form_state['values'][$field_name][$previous_langcode];
           $form_state['values'][$field_name][$previous_langcode] = array();
         }
       }
