diff --git a/core/modules/comment/comment.module b/core/modules/comment/comment.module
index c853e3a..7b6eda4 100644
--- a/core/modules/comment/comment.module
+++ b/core/modules/comment/comment.module
@@ -1118,6 +1118,7 @@ function comment_form_node_type_form_alter(&$form, $form_state) {
     );
     // @todo Remove this check once language settings are generalized.
     if (module_exists('translation_entity')) {
+      $comment_form = $form;
       $comment_form_state['translation_entity']['key'] = 'language_configuration';
       $form['comment'] += translation_entity_enable_widget('comment', 'comment_node_' . $form['#node_type']->type, $comment_form, $comment_form_state);
       array_unshift($form['#submit'], 'comment_translation_configuration_element_submit');
diff --git a/core/modules/comment/lib/Drupal/comment/Tests/CommentTranslationUITest.php b/core/modules/comment/lib/Drupal/comment/Tests/CommentTranslationUITest.php
new file mode 100644
index 0000000..75ca1d8
--- /dev/null
+++ b/core/modules/comment/lib/Drupal/comment/Tests/CommentTranslationUITest.php
@@ -0,0 +1,95 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\comment\Tests\CommentTranslationUITest.
+ */
+
+namespace Drupal\comment\Tests;
+
+use Drupal\translation_entity\Tests\EntityTranslationUITest;
+
+/**
+ * Tests the Comment Translation UI.
+ */
+class CommentTranslationUITest extends EntityTranslationUITest {
+
+  /**
+   * The subject of the test comment.
+   */
+  protected $subject;
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = array('language', 'translation_entity', 'node', 'comment');
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Comment translation UI',
+      'description' => 'Tests the basic comment translation UI.',
+      'group' => 'Comment',
+    );
+  }
+
+  /**
+   * Overrides \Drupal\simpletest\WebTestBase::setUp().
+   */
+  function setUp() {
+    $this->entityType = 'comment';
+    $this->nodeBundle = 'article';
+    $this->bundle = 'comment_node_' . $this->nodeBundle;
+    $this->testLanguageSelector = FALSE;
+    $this->subject = $this->randomName();
+    parent::setUp();
+  }
+
+  /**
+   * Overrides \Drupal\translation_entity\Tests\EntityTranslationUITest::setupBundle().
+   */
+  function setupBundle() {
+    parent::setupBundle();
+    $this->drupalCreateContentType(array('type' => $this->nodeBundle, 'name' => $this->nodeBundle));
+  }
+
+  /**
+   * Overrides \Drupal\translation_entity\Tests\EntityTranslationUITest::getTranslatorPermission().
+   */
+  function getTranslatorPermissions() {
+    return array('post comments', 'administer comments', "translate $this->entityType entities", 'edit original values');
+  }
+
+  /**
+   * Overrides \Drupal\translation_entity\Tests\EntityTranslationUITest::setupTestFields().
+   */
+  function setupTestFields() {
+    parent::setupTestFields();
+    $field = field_info_field('comment_body');
+    $field['translatable'] = TRUE;
+    field_update_field($field);
+  }
+
+  /**
+   * Overrides \Drupal\translation_entity\Tests\EntityTranslationUITest::createEntity().
+   */
+  protected function createEntity($values, $langcode) {
+    $node = $this->drupalCreateNode(array('type' => $this->nodeBundle));
+    $values['nid'] = $node->nid;
+    $values['uid'] = $node->uid;
+    return parent::createEntity($values, $langcode);
+  }
+
+  /**
+   * Overrides \Drupal\translation_entity\Tests\EntityTranslationUITest::getNewEntityValues().
+   */
+  protected function getNewEntityValues($langcode) {
+    // Comment subject is not translatable hence we use a fixed value.
+    return array(
+      'subject' => $this->subject,
+      'comment_body' => array(array('value' => $this->randomString(16))),
+    ) + parent::getNewEntityValues($langcode);
+  }
+
+}
diff --git a/core/modules/node/lib/Drupal/node/Tests/NodeTranslationUITest.php b/core/modules/node/lib/Drupal/node/Tests/NodeTranslationUITest.php
new file mode 100644
index 0000000..17c7fec
--- /dev/null
+++ b/core/modules/node/lib/Drupal/node/Tests/NodeTranslationUITest.php
@@ -0,0 +1,70 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\node\Tests\NodeTranslationUITest.
+ */
+
+namespace Drupal\node\Tests;
+
+use Drupal\translation_entity\Tests\EntityTranslationUITest;
+
+/**
+ * Tests the Node Translation UI.
+ */
+class NodeTranslationUITest extends EntityTranslationUITest {
+
+  /**
+   * The title of the test node.
+   */
+  protected $title;
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = array('language', 'translation_entity', 'node');
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Node translation UI',
+      'description' => 'Tests the node translation UI.',
+      'group' => 'Node',
+    );
+  }
+
+  /**
+   * Overrides \Drupal\simpletest\WebTestBase::setUp().
+   */
+  function setUp() {
+    $this->entityType = 'node';
+    $this->bundle = 'article';
+    $this->title = $this->randomName();
+    parent::setUp();
+  }
+
+  /**
+   * Overrides \Drupal\translation_entity\Tests\EntityTranslationUITest::setupBundle().
+   */
+  protected function setupBundle() {
+    parent::setupBundle();
+    $this->drupalCreateContentType(array('type' => $this->bundle, 'name' => $this->bundle));
+  }
+
+  /**
+   * Overrides \Drupal\translation_entity\Tests\EntityTranslationUITest::getTranslatorPermission().
+   */
+  function getTranslatorPermissions() {
+    return array("edit any $this->bundle content", "translate $this->entityType entities", 'edit original values');
+  }
+
+  /**
+   * Overrides \Drupal\translation_entity\Tests\EntityTranslationUITest::getNewEntityValues().
+   */
+  protected function getNewEntityValues($langcode) {
+    // Node title is not translatable yet, hence we use a fixed value.
+    return array('title' => $this->title) + parent::getNewEntityValues($langcode);
+  }
+
+}
diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermTranslationUITest.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermTranslationUITest.php
new file mode 100644
index 0000000..907ce87
--- /dev/null
+++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermTranslationUITest.php
@@ -0,0 +1,89 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\taxonomy\Tests\TermTranslationUITest.
+ */
+
+namespace Drupal\taxonomy\Tests;
+
+use Drupal\translation_entity\Tests\EntityTranslationUITest;
+
+/**
+ * Tests the Term Translation UI.
+ */
+class TermTranslationUITest extends EntityTranslationUITest {
+
+  /**
+   * The name of the test taxonomy term.
+   */
+  protected $name;
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = array('language', 'translation_entity', 'taxonomy');
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Taxonomy term translation UI',
+      'description' => 'Tests the basic term translation UI.',
+      'group' => 'Taxonomy',
+    );
+  }
+
+  /**
+   * Overrides \Drupal\simpletest\WebTestBase::setUp().
+   */
+  function setUp() {
+    $this->entityType = 'taxonomy_term';
+    $this->bundle = 'tags';
+    $this->name = $this->randomName();
+    parent::setUp();
+  }
+
+  /**
+   * Overrides \Drupal\translation_entity\Tests\EntityTranslationUITest::setupBundle().
+   */
+  protected function setupBundle() {
+    parent::setupBundle();
+
+    // Create a vocabulary.
+    $vocabulary = entity_create('taxonomy_vocabulary', array(
+      'name' => $this->bundle,
+      'description' => $this->randomName(),
+      'machine_name' => $this->bundle,
+      'langcode' => LANGUAGE_NOT_SPECIFIED,
+      'help' => '',
+      'weight' => mt_rand(0, 10),
+    ));
+    taxonomy_vocabulary_save($vocabulary);
+  }
+
+  /**
+   * Overrides \Drupal\translation_entity\Tests\EntityTranslationUITest::getTranslatorPermission().
+   */
+  function getTranslatorPermissions() {
+    return array('administer taxonomy', "translate $this->entityType entities", 'edit original values');
+  }
+
+  /**
+   * Overrides \Drupal\translation_entity\Tests\EntityTranslationUITest::createEntity().
+   */
+  protected function createEntity($values, $langcode) {
+    $vocabulary = taxonomy_vocabulary_machine_name_load($this->bundle);
+    $values['vid'] = $vocabulary->id();
+    return parent::createEntity($values, $langcode);
+  }
+
+  /**
+   * Overrides \Drupal\translation_entity\Tests\EntityTranslationUITest::getNewEntityValues().
+   */
+  protected function getNewEntityValues($langcode) {
+    // Term name is not translatable hence we use a fixed value.
+    return array('name' => $this->name) + parent::getNewEntityValues($langcode);
+  }
+
+}
diff --git a/core/modules/translation_entity/lib/Drupal/translation_entity/EntityTranslationController.php b/core/modules/translation_entity/lib/Drupal/translation_entity/EntityTranslationController.php
index 6966d0b..26a2699 100644
--- a/core/modules/translation_entity/lib/Drupal/translation_entity/EntityTranslationController.php
+++ b/core/modules/translation_entity/lib/Drupal/translation_entity/EntityTranslationController.php
@@ -14,7 +14,18 @@
  */
 class EntityTranslationController implements EntityTranslationControllerInterface {
 
+  /**
+   * The type of the entity being translated.
+   *
+   * @var string
+   */
   protected $entityType;
+
+  /**
+   * The entity info of the entity being translated.
+   *
+   * @var array
+   */
   protected $entityInfo;
 
   /**
@@ -141,6 +152,7 @@ public function entityFormAlter(array &$form, array &$form_state, EntityInterfac
         '#collapsed' => TRUE,
         '#tree' => TRUE,
         '#weight' => -100,
+        '#multilingual' => TRUE,
         'source' => array(
           '#type' => 'select',
           '#default_value' => $source_langcode,
diff --git a/core/modules/translation_entity/lib/Drupal/translation_entity/EntityTranslationControllerInterface.php b/core/modules/translation_entity/lib/Drupal/translation_entity/EntityTranslationControllerInterface.php
index 025d550..ed08fc0 100644
--- a/core/modules/translation_entity/lib/Drupal/translation_entity/EntityTranslationControllerInterface.php
+++ b/core/modules/translation_entity/lib/Drupal/translation_entity/EntityTranslationControllerInterface.php
@@ -75,13 +75,15 @@
  *     );
  *   }
  * @endcode
+ *
+ * @see \Drupal\Core\Entity\EntityManager
  */
 interface EntityTranslationControllerInterface {
 
   /**
    * Returns the base path for the current entity.
    *
-   * @param Drupal\Core\Entity\EntityInterface $entity
+   * @param \Drupal\Core\Entity\EntityInterface $entity
    *   The entity to the path should refer to.
    *
    * @return string
@@ -92,7 +94,7 @@ public function getBasePath(EntityInterface $entity);
   /**
    * Returns the path of the entity edit form.
    *
-   * @param Drupal\Core\Entity\EntityInterface $entity
+   * @param \Drupal\Core\Entity\EntityInterface $entity
    *   The entity to the path should refer to.
    *
    * @return string
@@ -103,7 +105,7 @@ public function getEditPath(EntityInterface $entity);
   /**
    * Returns the path of the entity view page.
    *
-   * @param Drupal\Core\Entity\EntityInterface $entity
+   * @param \Drupal\Core\Entity\EntityInterface $entity
    *   The entity to the path should refer to.
    *
    * @return string
@@ -114,7 +116,7 @@ public function getViewPath(EntityInterface $entity);
   /**
    * Checks if the user can perform the given operation on the wrapped entity.
    *
-   * @param Drupal\Core\Entity\EntityInterface $entity
+   * @param \Drupal\Core\Entity\EntityInterface $entity
    *   The entity access should be checked for.
    * @param string $op
    *   The operation to be performed. Possible values are:
@@ -132,7 +134,7 @@ public function getAccess(EntityInterface $entity, $op);
   /**
    * Checks if a user is allowed to edit the given translation.
    *
-   * @param Drupal\Core\Entity\EntityInterface $entity
+   * @param \Drupal\Core\Entity\EntityInterface $entity
    *   The entity whose translation has to be accessed.
    * @param string $langcode
    *   The language code identifying the translation to be accessed.
@@ -156,7 +158,7 @@ public function getSourceLangcode(array $form_state);
   /**
    * Removes the translation values from the given entity.
    *
-   * @param Drupal\Core\Entity\EntityInterface $entity
+   * @param \Drupal\Core\Entity\EntityInterface $entity
    *   The entity whose values should be removed.
    * @param string $langcode
    *   The language code identifying the translation being deleted.
@@ -166,7 +168,7 @@ public function removeTranslation(EntityInterface $entity, $langcode);
   /**
    * Marks translations as outdated.
    *
-   * @param Drupal\Core\Entity\EntityInterface $entity
+   * @param \Drupal\Core\Entity\EntityInterface $entity
    *   The entity being translated.
    * @param string $langcode
    *   (optional) The language code of the updated language: all the other
@@ -181,7 +183,7 @@ public function retranslate(EntityInterface $entity, $langcode = NULL);
    *   The entity form to be altered to provide the translation workflow.
    * @param array $form_state
    *   The form state array.
-   * @param Drupal\Core\Entity\EntityInterface $entity
+   * @param \Drupal\Core\Entity\EntityInterface $entity
    *   The entity being created or edited.
    */
   public function entityFormAlter(array &$form, array &$form_state, EntityInterface $entity);
diff --git a/core/modules/translation_entity/lib/Drupal/translation_entity/Tests/EntityTestTranslationUITest.php b/core/modules/translation_entity/lib/Drupal/translation_entity/Tests/EntityTestTranslationUITest.php
new file mode 100644
index 0000000..6f0f9c0
--- /dev/null
+++ b/core/modules/translation_entity/lib/Drupal/translation_entity/Tests/EntityTestTranslationUITest.php
@@ -0,0 +1,55 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\entity\Tests\EntityTestTranslationUITest.
+ */
+
+namespace Drupal\translation_entity\Tests;
+
+/**
+ * Tests the Entity Test Translation UI.
+ */
+class EntityTestTranslationUITest extends EntityTranslationUITest {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = array('language', 'translation_entity', 'entity_test');
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Entity Test Translation UI',
+      'description' => 'Tests the test entity translation UI.',
+      'group' => 'Entity Translation UI',
+    );
+  }
+
+  /**
+   * Overrides \Drupal\simpletest\WebTestBase::setUp().
+   */
+  function setUp() {
+    $this->entityType = 'entity_test';
+    parent::setUp();
+  }
+
+  /**
+   * Overrides \Drupal\translation_entity\Tests\EntityTranslationUITest::getTranslatorPermission().
+   */
+  function getTranslatorPermissions() {
+    return array('administer entity_test content', "translate $this->entityType entities", 'edit original values');
+  }
+
+  /**
+   * Overrides \Drupal\translation_entity\Tests\EntityTranslationUITest::getNewEntityValues().
+   */
+  protected function getNewEntityValues($langcode) {
+    return array(
+      'name' => $this->randomName(),
+      'user_id' => mt_rand(1, 128),
+    ) + parent::getNewEntityValues($langcode);
+  }
+
+}
diff --git a/core/modules/translation_entity/lib/Drupal/translation_entity/Tests/EntityTranslationUITest.php b/core/modules/translation_entity/lib/Drupal/translation_entity/Tests/EntityTranslationUITest.php
index a0876a4..934ed62 100644
--- a/core/modules/translation_entity/lib/Drupal/translation_entity/Tests/EntityTranslationUITest.php
+++ b/core/modules/translation_entity/lib/Drupal/translation_entity/Tests/EntityTranslationUITest.php
@@ -7,12 +7,17 @@
 
 namespace Drupal\translation_entity\Tests;
 
+use Drupal\Core\Entity\DatabaseStorageControllerNG;
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Entity\EntityNG;
+use Drupal\Core\Language\Language;
+use Drupal\Core\TypedData\ComplexDataInterface;
 use Drupal\simpletest\WebTestBase;
 
 /**
  * Tests the Entity Translation UI.
  */
-class EntityTranslationUITest extends WebTestBase {
+abstract class EntityTranslationUITest extends WebTestBase {
 
   /**
    * The enabled languages.
@@ -22,170 +27,291 @@ class EntityTranslationUITest extends WebTestBase {
   protected $langcodes;
 
   /**
-   * Modules to enable.
+   * The entity type being tested.
    *
-   * @var array
+   * @var string
    */
-  public static $modules = array('language', 'translation_entity', 'entity_test');
+  protected $entityType;
 
-  public static function getInfo() {
-    return array(
-      'name' => 'Translation UI',
-      'description' => 'Tests the basic entity translation UI.',
-      'group' => 'Entity Translation UI',
-    );
-  }
+  /**
+   * The bundle being tested.
+   *
+   * @var string
+   */
+  protected $bundle;
+
+  /**
+   * The name of the field used to test translation.
+   *
+   * @var string
+   */
+  protected $fieldName;
 
+  /**
+   * Whether the behavior of the language selector should be tested.
+   *
+   * @var boolean
+   */
+  protected $testLanguageSelector = TRUE;
+
+
+  /**
+   * Overrides \Drupal\simpletest\WebTestBase::setUp().
+   */
   function setUp() {
     parent::setUp();
 
-    $admin_user = $this->drupalCreateUser(array('administer languages', 'access administration pages'));
-    $this->drupalLogin($admin_user);
+    $this->setupLanguages();
+    $this->setupBundle();
+    $this->enableTranslation();
+    $this->setupTranslator();
+    $this->setupTestFields();
+  }
 
-    $languages = array('it' => 'Italian', 'fr' => 'French');
-    $this->langcodes = array_keys($languages);
+  /**
+   * Enables additional languages.
+   */
+  protected function setupLanguages() {
+    $this->langcodes = array('it', 'fr');
+    foreach ($this->langcodes as $langcode) {
+      language_save(new Language(array('langcode' => $langcode)));
+    }
     array_unshift($this->langcodes, language_default()->langcode);
+  }
 
-    // Add predefined language.
-    foreach ($languages as $langcode => $name) {
-      $edit = array('predefined_langcode' => $langcode);
-      $this->drupalPost('admin/config/regional/language/add', $edit, t('Add language'));
-      $this->assertText($name, 'Language added successfully.');
+  /**
+   * Creates or initializes the bundle date if needed.
+   */
+  protected function setupBundle() {
+    if (empty($this->bundle)) {
+      $this->bundle = $this->entityType;
     }
+  }
 
-    // Enable translation for the entity_test entity type and ensure the change
-    // is picked up.
-    translation_entity_set_config('entity_test', 'entity_test', 'enabled', TRUE);
+  /**
+   * Enables translation for the current entity type and bundle.
+   */
+  protected function enableTranslation() {
+    // Enable translation for the current entity type and ensure the change is
+    // picked up.
+    translation_entity_set_config($this->entityType, $this->bundle, 'enabled', TRUE);
     drupal_static_reset();
     entity_info_cache_clear();
     menu_router_rebuild();
+  }
 
-    $translator = $this->drupalCreateUser(array('administer entity_test content', 'translate entity_test entities', 'edit original values'));
+  /**
+   * Returns an array of permissions needed for the translator.
+   */
+  abstract function getTranslatorPermissions();
+
+  /**
+   * Creates and activates a translator user.
+   */
+  protected function setupTranslator() {
+    $translator = $this->drupalCreateUser($this->getTranslatorPermissions());
     $this->drupalLogin($translator);
   }
 
   /**
-   * Tests the basic translation UI.
+   * Creates the test fields.
    */
-  function testTranslationUI() {
-    // Make the test field translatable.
-    $field = field_info_field('field_test_text');
-    $field['translatable'] = TRUE;
-    field_update_field($field);
+  protected function setupTestFields() {
+    $this->fieldName = 'field_test_et_ui_test';
 
-    // Create a new test entity with original values in the default language.
-    $default_langcode = language_default()->langcode;
+    $field = array(
+      'field_name' => $this->fieldName,
+      'type' => 'text',
+      'cardinality' => 1,
+      'translatable' => TRUE,
+    );
+    field_create_field($field);
 
-    $values[$default_langcode] = array(
-      'langcode' => $default_langcode,
-      'name' => $this->randomName(8),
-      'user_id' => mt_rand(1, 128),
-      'field_test_text' => $this->randomName(16),
+    $instance = array(
+      'entity_type' => $this->entityType,
+      'field_name' => $this->fieldName,
+      'bundle' => $this->bundle,
+      'label' => 'Test translatable text-field',
+      'widget' => array(
+        'type' => 'text_textfield',
+        'weight' => 0,
+      ),
     );
+    field_create_instance($instance);
+  }
 
-    $this->drupalPost('entity-test/add', $this->getEditValues($values, $default_langcode, TRUE), t('Save'));
-    $entity = $this->loadEntityByName($values[$default_langcode]['name']);
+  /**
+   * Tests the basic translation UI.
+   */
+  function testTranslationUI() {
+    // Create a new test entity with original values in the default language.
+    $default_langcode = $this->langcodes[0];
+    $values[$default_langcode] = $this->getNewEntityValues($default_langcode);
+    $id = $this->createEntity($values[$default_langcode], $default_langcode);
+    $entity = entity_load($this->entityType, $id, TRUE);
     $this->assertTrue($entity, t('Entity found in the database.'));
 
-    $translation = $entity->getTranslation($default_langcode);
+    $translation = $this->getTranslation($entity, $default_langcode);
     foreach ($values[$default_langcode] as $property => $value) {
-      if ($property != 'langcode') {
-        // @todo Remove this workaround when field default language is correctly
-        // handled.
-        $stored_value = $property != 'field_test_text' ? $translation->get($property)->value : $entity->values['field_test_text'][$default_langcode][0]['value'];
-        $message = format_string('@property correctly stored in the default language.', array('@property' => $property));
-        $this->assertEqual($stored_value, $value, $message);
-      }
+      $stored_value = $this->getValue($translation, $property, $default_langcode);
+      $value = is_array($value) ? $value[0]['value'] : $value;
+      $message = format_string('@property correctly stored in the default language.', array('@property' => $property));
+      $this->assertIdentical($stored_value, $value, $message);
     }
 
     // Add an entity translation.
     $langcode = 'it';
-    $values[$langcode] = array(
-      'name' => $this->randomName(8),
-      'user_id' => mt_rand(1, 128),
-      'field_test_text' => $this->randomName(16),
-    );
+    $values[$langcode] = $this->getNewEntityValues($langcode);
 
-    $this->drupalPost($langcode . '/entity-test/manage/' . $entity->id() . '/translations/add/' . $default_langcode . '/' . $langcode, $this->getEditValues($values, $langcode), t('Save'));
-    $this->assertNoFieldByXPath('//select[@id="edit-langcode"]', NULL, 'Language selector correclty disabled on translations.');
-    $this->assertNoRaw('all languages', t('All form elements are translatable.'));
-    $entity = entity_test_load($entity->id(), TRUE);
+    $controller = translation_entity_controller($this->entityType);
+    $base_path = $controller->getBasePath($entity);
+    $path = $langcode . '/' . $base_path . '/translations/add/' . $default_langcode . '/' . $langcode;
+    $this->drupalPost($path, $this->getEditValues($values, $langcode), t('Save'));
+    if ($this->testLanguageSelector) {
+      $this->assertNoFieldByXPath('//select[@id="edit-langcode"]', NULL, 'Language selector correclty disabled on translations.');
+    }
+    $entity = entity_load($this->entityType, $entity->id(), TRUE);
 
     // Switch the source language.
     $langcode = 'fr';
     $source_langcode = 'it';
     $edit = array('source_langcode[source]' => $source_langcode);
-    $this->drupalPost($langcode . '/entity-test/manage/' . $entity->id() . '/translations/add/' . $default_langcode . '/' . $langcode, $edit, t('Change'));
-    $this->assertFieldByXPath('//input[@name="field_test_text[fr][0][value]"]', $values[$source_langcode]['field_test_text'], 'Source language correctly switched.');
+    $path = $langcode . '/' . $base_path . '/translations/add/' . $default_langcode . '/' . $langcode;
+    $this->drupalPost($path, $edit, t('Change'));
+    $this->assertFieldByXPath("//input[@name=\"{$this->fieldName}[fr][0][value]\"]", $values[$source_langcode][$this->fieldName][0]['value'], 'Source language correctly switched.');
 
     // Add another translation and mark the other ones as outdated.
-    $values[$langcode] = array(
-      'name' => $this->randomName(8),
-      'user_id' => mt_rand(1, 128),
-      'field_test_text' => $this->randomName(16),
-    );
+    $values[$langcode] = $this->getNewEntityValues($langcode);
     $edit = $this->getEditValues($values, $langcode) + array('translation[retranslate]' => TRUE);
-    $this->drupalPost(NULL, $edit, t('Save'));
-    $entity = entity_test_load($entity->id(), TRUE);
+    $this->drupalPost($path, $edit, t('Save'));
+    $entity = entity_load($this->entityType, $entity->id(), TRUE);
 
     // Check that the entered values have been correctly stored.
     foreach ($values as $langcode => $property_values) {
-      $translation = $entity->getTranslation($langcode);
+      $translation = $this->getTranslation($entity, $langcode);
       foreach ($property_values as $property => $value) {
-        if ($property != 'langcode') {
-          $stored_value = $translation->get($property);
-          // @todo Remove this workaround when field default language is correctly
-          // handled.
-          $stored_value = $property != 'field_test_text' ? $translation->get($property)->value : $entity->values['field_test_text'][$langcode][0]['value'];
-          $message = format_string('%property correctly stored with language %language.', array('%property' => $property, '%language' => $langcode));
-          $this->assertEqual($stored_value, $value, $message);
-        }
+        $stored_value = $this->getValue($translation, $property, $langcode);
+        $value = is_array($value) ? $value[0]['value'] : $value;
+        $message = format_string('%property correctly stored with language %language.', array('%property' => $property, '%language' => $langcode));
+        $this->assertEqual($stored_value, $value, $message);
       }
     }
 
     // Check that every translation has the correct "outdated" status.
     foreach ($this->langcodes as $enabled_langcode) {
       $prefix = $enabled_langcode != $default_langcode ? $enabled_langcode . '/' : '';
-      $this->drupalGet($prefix . 'entity-test/manage/' . $entity->id() . '/edit');
+      $path = $prefix . $controller->getEditPath($entity);
+      $this->drupalGet($path);
       if ($enabled_langcode == $langcode) {
         $this->assertFieldByXPath('//input[@name="translation[retranslate]"]', FALSE, 'The retranslate flag is not checked by default.');
       }
       else {
         $this->assertFieldByXPath('//input[@name="translation[translate]"]', TRUE, 'The translate flag is checked by default.');
         $edit = array('translation[translate]' => FALSE);
-        $this->drupalPost(NULL, $edit, t('Save'));
+        $this->drupalPost($path, $edit, t('Save'));
+        $this->drupalGet($path);
         $this->assertFieldByXPath('//input[@name="translation[retranslate]"]', FALSE, 'The retranslate flag is now shown.');
-        $entity = entity_test_load($entity->id(), TRUE);
+        $entity = entity_load($this->entityType, $entity->id(), TRUE);
         $this->assertFalse($entity->retranslate[$enabled_langcode], 'The "outdated" status has been correctly stored.');
       }
     }
 
     // Confirm and delete a translation.
-    $this->drupalPost(NULL, array(), t('Delete translation'));
+    $this->drupalPost($path, array(), t('Delete translation'));
     $this->drupalPost(NULL, array(), t('Delete'));
-    $entity = entity_test_load($entity->id(), TRUE);
+    $entity = entity_load($this->entityType, $entity->id(), TRUE);
     $translations = $entity->getTranslationLanguages();
     $this->assertTrue(count($translations) == 2 && empty($translations[$enabled_langcode]), 'Translation successfully deleted.');
   }
 
   /**
+   * Creates the entity to be translated.
+   *
+   * @param array $values
+   *   An array of initial values for the entity.
+   * @param string $langcode
+   *   The initial language code of the entity.
+   *
+   * @return
+   *   The entity id.
+   */
+  protected function createEntity($values, $langcode) {
+    $entity_values = $values;
+    $entity_values['langcode'] = $langcode;
+    $info = entity_get_info($this->entityType);
+    if (!empty($info['entity_keys']['bundle'])) {
+      $entity_values[$info['entity_keys']['bundle']] = $this->bundle;
+    }
+    $controller = entity_get_controller($this->entityType);
+    if (!($controller instanceof DatabaseStorageControllerNG)) {
+      foreach ($values as $property => $value) {
+        if (is_array($value)) {
+          $entity_values[$property] = array($langcode => $value);
+        }
+      }
+    }
+    $entity = entity_create($this->entityType, $entity_values);
+    $entity->save();
+    return $entity->id();
+  }
+
+  /**
+   * Returns an array of entity field values to be tested.
+   */
+  protected function getNewEntityValues($langcode) {
+    return array($this->fieldName => array(array('value' => $this->randomName(16))));
+  }
+
+  /**
    * Returns an edit array containing the values to be posted.
    */
   protected function getEditValues($values, $langcode, $new = FALSE) {
     $edit = $values[$langcode];
     $langcode = $new ? LANGUAGE_NOT_SPECIFIED : $langcode;
-    $edit["field_test_text[$langcode][0][value]"] = $edit['field_test_text'];
-    unset($edit['field_test_text']);
+    foreach ($values[$langcode] as $property => $value) {
+      if (is_array($value)) {
+        $edit["{$property}[$langcode][0][value]"] = $value[0]['value'];
+        unset($edit[$property]);
+      }
+    }
     return $edit;
   }
 
   /**
-   * Loads a test entity by name.
+   * Returns the translation object to use to retrieve the translated values.
+   *
+   * @param \Drupal\Core\Enitity\EntityInterface $entity
+   *   The entity being tested.
+   * @param string $langcode
+   *   The language code identifying the translation to be retrieved.
    *
-   * @return Drupal\entity_test\EntityTest
-   *   A test entity matching the given name.
+   * @return \Drupal\Core\TypedData\TranslatableInterface
+   *   The translation object to act on.
    */
-  protected function loadEntityByName($name) {
-    return current(entity_load_multiple_by_properties('entity_test', array('name' => $name)));
+  protected function getTranslation(EntityInterface $entity, $langcode) {
+    return $entity instanceof EntityNG ? $entity->getTranslation($langcode) : $entity;
   }
+
+  /**
+   * Returns the value for the specified property in the given language.
+   *
+   * @param \Drupal\Core\TypedData\TranslatableInterface $translation
+   *   The translation object the property value should be retrieved from.
+   * @param string $property
+   *   The property name.
+   * @param string $langcode
+   *   The property value.
+   *
+   * @return
+   *   The property value.
+   */
+  protected function getValue(ComplexDataInterface $translation, $property, $langcode) {
+    if (($translation instanceof EntityInterface) && !($translation instanceof EntityNG)) {
+      return is_array($translation->$property) ? $translation->{$property}[$langcode][0]['value'] : $translation->$property;
+    }
+    else {
+      return $translation->get($property)->value;
+    }
+  }
+
 }
diff --git a/core/modules/translation_entity/translation_entity.module b/core/modules/translation_entity/translation_entity.module
index 547903a..b0c8526 100644
--- a/core/modules/translation_entity/translation_entity.module
+++ b/core/modules/translation_entity/translation_entity.module
@@ -225,7 +225,7 @@ function translation_entity_menu_alter(array &$items) {
 /**
  * Access callback for the translation overview page.
  *
- * @param Drupal\Core\Entity\EntityInterface $entity
+ * @param \Drupal\Core\Entity\EntityInterface $entity
  *   The entity whose translation overview should be displayed.
  */
 function translation_entity_translate_access(EntityInterface $entity) {
@@ -236,11 +236,11 @@ function translation_entity_translate_access(EntityInterface $entity) {
 /**
  * Access callback for the translation addition page.
  *
- * @param Drupal\Core\Entity\EntityInterface $entity
+ * @param \Drupal\Core\Entity\EntityInterface $entity
  *   The entity being translated.
- * @param Drupal\Core\Language\Language $source
+ * @param \Drupal\Core\Language\Language $source
  *   The language of the values being translated.
- * @param Drupal\Core\Language\Language $target
+ * @param \Drupal\Core\Language\Language $target
  *   The language of the translated values.
  */
 function translation_entity_add_access(EntityInterface $entity, Language $source = NULL, Language $target = NULL) {
@@ -347,7 +347,7 @@ function translation_entity_enabled($entity_type, $bundle = NULL, $skip_handler
  * @param string $entity_type
  *   The type of the entity being translated.
  *
- * @return Drupal\translation_entity\EntityTranslationControllerInterface
+ * @return \Drupal\translation_entity\EntityTranslationControllerInterface
  *   An instance of the entity translation controller interface.
  */
 function translation_entity_controller($entity_type) {
@@ -362,7 +362,7 @@ function translation_entity_controller($entity_type) {
  * @param array $form_state
  *   The form state array holding the entity form controller.
  *
- * @return Drupal\Core\Entity\EntityFormControllerInterface;
+ * @return \Drupal\Core\Entity\EntityFormControllerInterface;
  *   An instance of the entity translation form interface or FALSE if not an
  *   entity form.
  */
@@ -373,7 +373,7 @@ function translation_entity_form_controller(array $form_state) {
 /**
  * Checks whether an entity translation is accessible.
  *
- * @param Drupal\Core\Entity\EntityInterface $entity
+ * @param \Drupal\Core\Entity\EntityInterface $entity
  *   The entity to be accessed.
  * @param string $langcode
  *   The language of the translation to be accessed.
diff --git a/core/modules/translation_entity/translation_entity.pages.inc b/core/modules/translation_entity/translation_entity.pages.inc
index b7b9a8c..be06e6a 100644
--- a/core/modules/translation_entity/translation_entity.pages.inc
+++ b/core/modules/translation_entity/translation_entity.pages.inc
@@ -12,7 +12,7 @@
 /**
  * Translations overview page callback.
  *
- * @param Drupal\Core\Entity\EntityInterface $entity
+ * @param \Drupal\Core\Entity\EntityInterface $entity
  *   The entity whose translation overview should be displayed.
  */
 function translation_entity_overview(EntityInterface $entity) {
@@ -184,7 +184,7 @@ function translation_entity_add_page(EntityInterface $entity, Language $source =
   // @todo Exploit the upcoming hook_entity_prepare() when available.
   translation_entity_prepare_translation($entity, $source, $target);
   $info = $entity->entityInfo();
-  $operation = isset($info['default operation']) ? $info['default operation'] : 'default';
+  $operation = isset($info['default_operation']) ? $info['default_operation'] : 'default';
   $form_state = entity_form_state_defaults($entity, $operation, $target->langcode);
   $form_state['translation_entity']['source'] = $source;
   $form_state['translation_entity']['target'] = $target;
@@ -195,11 +195,11 @@ function translation_entity_add_page(EntityInterface $entity, Language $source =
 /**
  * Populates target values with the source values.
  *
- * @param Drupal\Core\Entity\EntityInterface $entity
+ * @param \Drupal\Core\Entity\EntityInterface $entity
  *   The entitiy being translated.
- * @param Drupal\Core\Language\Language $source
+ * @param \Drupal\Core\Language\Language $source
  *   The language to be used as source.
- * @param Drupal\Core\Language\Language $target
+ * @param \Drupal\Core\Language\Language $target
  *   The language to be used as target.
  */
 function translation_entity_prepare_translation(EntityInterface $entity, Language $source, Language $target) {
@@ -208,19 +208,10 @@ function translation_entity_prepare_translation(EntityInterface $entity, Languag
   if ($entity instanceof EntityNG) {
     $source_translation = $entity->getTranslation($source->langcode);
     $target_translation = $entity->getTranslation($target->langcode);
-
     foreach ($target_translation->getPropertyDefinitions() as $property_name => $definition) {
-      if (!isset($instances[$property_name])) {
-        // @todo Actually retrieving the property value should not be necessary.
-        $target_translation->$property_name = $source_translation->$property_name->value;
-      }
-      else {
-        $entity->setCompatibilityMode(TRUE);
-        $value = $entity->$property_name;
-        $value[$target->langcode] = isset($value[$source->langcode]) ? $value[$source->langcode] : NULL;
-        $entity->$property_name = $value;
-        $entity->setCompatibilityMode(FALSE);
-      }
+      // @todo The value part should not be needed. Remove it as soon as things
+      //   do not break.
+      $target_translation->$property_name->value = $source_translation->$property_name->value;
     }
   }
   else {
@@ -228,7 +219,7 @@ function translation_entity_prepare_translation(EntityInterface $entity, Languag
       $field = field_info_field($field_name);
       if (!empty($field['translatable'])) {
         $value = $entity->get($field_name);
-        $value[$target->langcode] = $value[$source->langcode];
+        $value[$target->langcode] = isset($value[$source->langcode]) ? $value[$source->langcode] : array();
         $entity->set($field_name, $value);
       }
     }
diff --git a/core/modules/user/lib/Drupal/user/ProfileTranslationController.php b/core/modules/user/lib/Drupal/user/ProfileTranslationController.php
index 91e129b..582644b 100644
--- a/core/modules/user/lib/Drupal/user/ProfileTranslationController.php
+++ b/core/modules/user/lib/Drupal/user/ProfileTranslationController.php
@@ -36,7 +36,7 @@ function entityFormSave(array $form, array &$form_state) {
       // We need a redirect here, otherwise we would get an access denied page
       // since the current URL would be preserved and we would try to add a
       // translation for a language that already has a translation.
-      $form_state['redirect'] = $this->getEditPath($entity);
+      $form_state['redirect'] = $this->getViewPath($entity);
     }
   }
 }
diff --git a/core/modules/user/lib/Drupal/user/Tests/UserTranslationUITest.php b/core/modules/user/lib/Drupal/user/Tests/UserTranslationUITest.php
new file mode 100644
index 0000000..ae5528f
--- /dev/null
+++ b/core/modules/user/lib/Drupal/user/Tests/UserTranslationUITest.php
@@ -0,0 +1,62 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\user\Tests\UserTranslationUITest.
+ */
+
+namespace Drupal\user\Tests;
+
+use Drupal\translation_entity\Tests\EntityTranslationUITest;
+
+/**
+ * Tests the User Translation UI.
+ */
+class UserTranslationUITest extends EntityTranslationUITest {
+
+  /**
+   * The user name of the test user.
+   */
+  protected $name;
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = array('language', 'translation_entity', 'user');
+
+  public static function getInfo() {
+    return array(
+      'name' => 'User translation UI',
+      'description' => 'Tests the user translation UI.',
+      'group' => 'User',
+    );
+  }
+
+  /**
+   * Overrides \Drupal\simpletest\WebTestBase::setUp().
+   */
+  function setUp() {
+    $this->entityType = 'user';
+    $this->testLanguageSelector = FALSE;
+    $this->name = $this->randomName();
+    parent::setUp();
+  }
+
+  /**
+   * Overrides \Drupal\translation_entity\Tests\EntityTranslationUITest::getTranslatorPermission().
+   */
+  function getTranslatorPermissions() {
+    return array('administer users', "translate $this->entityType entities", 'edit original values');
+  }
+
+  /**
+   * Overrides \Drupal\translation_entity\Tests\EntityTranslationUITest::getNewEntityValues().
+   */
+  protected function getNewEntityValues($langcode) {
+    // User name is not translatable hence we use a fixed value.
+    return array('name' => $this->name) + parent::getNewEntityValues($langcode);
+  }
+
+}
