diff --git a/core/modules/content_translation/content_translation.module b/core/modules/content_translation/content_translation.module
index a6f7987..c1ea11a 100644
--- a/core/modules/content_translation/content_translation.module
+++ b/core/modules/content_translation/content_translation.module
@@ -60,6 +60,16 @@ function content_translation_module_implements_alter(&$implementations, $hook) {
       unset($implementations['content_translation']);
       $implementations['content_translation'] = $group;
       break;
+
+    // Since in this hook implementation we are changing the form language, by
+    // acting first we minimize the risk of having inconsistent behaviors due to
+    // different hook_entity_prepare_form() implementations assuming different
+    // form languages.
+    case 'entity_prepare_form':
+      $group = $implementations['content_translation'];
+      unset($implementations['content_translation']);
+      $implementations = array('content_translation' => $group) + $implementations;
+      break;
   }
 }
 
@@ -325,6 +335,84 @@ function _content_translation_menu_strip_loaders($path) {
 }
 
 /**
+ * Implements hook_entity_prepare_form().
+ */
+function content_translation_entity_prepare_form(EntityInterface $entity, $form_display, $operation, array &$form_state) {
+  if ($entity instanceof ContentEntityInterface) {
+    $languages = language_list();
+    $source = Drupal::request()->get('content_translation_source');
+    $target = Drupal::request()->get('content_translation_target');
+    content_translation_prepare_translation_form($entity, isset($languages[$source]) ? $source : FALSE, isset($languages[$target]) ? $target : NULL, $form_state);
+  }
+}
+
+/**
+ * Prepares the entity and the form state to display a translation form.
+ *
+ * @param ContentEntityInterface $entity
+ *   The entity being translated.
+ * @param string $source
+ *   The language code to be used as source.
+ * @param string $target
+ *   The language code to be used as target.
+ * @param array $form_state
+ *   An associative array representing the state of the form.
+ */
+function content_translation_prepare_translation_form(ContentEntityInterface $entity, $source, $target, array &$form_state) {
+  if (empty($form_state['content_translation']['prepared']) && $entity->isTranslatable() && content_translation_access($entity, $source ? 'create' : 'update')) {
+    // Avoid preparing the entity form twice.
+    $form_state['content_translation']['prepared'] = TRUE;
+
+    // If no valid translation language is specified, we just let the entity
+    // form controller determine most appropriate form language based on the
+    // entity data.
+    if (isset($target) && ($source || ($translations = $entity->getTranslationLanguages()) && isset($translations[$target]))) {
+      $form_state['langcode'] = $target;
+      $form_state['content_translation']['target'] = $target;
+    }
+    $form_state['content_translation']['source'] = $source;
+
+    // Translators do not see the full entity form, just the translatable bits.
+    $form_state['content_translation']['translation_form'] = !$entity->access('update');
+
+    // If we have a source language defined we are creating a new translation
+    // for which we need to prepare the initial values.
+    if ($source) {
+      content_translation_prepare_translation($entity, $source, $target);
+    }
+  }
+}
+
+/**
+ * Populates target values with the source values.
+ *
+ * @param \Drupal\Core\Entity\EntityInterface $entity
+ *   The entity being translated.
+ * @param string $source
+ *   The language code to be used as source.
+ * @param string $target
+ *   The language code to be used as target.
+ */
+function content_translation_prepare_translation(EntityInterface $entity, $source, $target) {
+  // @todo Unify field and property handling.
+  if ($entity instanceof ContentEntityInterface) {
+    $source_translation = $entity->getTranslation($source);
+    $entity->addTranslation($target, $source_translation->getPropertyValues());
+  }
+  else {
+    $instances = field_info_instances($entity->entityType(), $entity->bundle());
+    foreach ($instances as $field_name => $instance) {
+      $field = field_info_field($entity->entityType(), $field_name);
+      if (!empty($field['translatable'])) {
+        $value = $entity->get($field_name);
+        $value[$target] = isset($value[$source]) ? $value[$source] : array();
+        $entity->set($field_name, $value);
+      }
+    }
+  }
+}
+
+/**
  * Access callback for the translation overview page.
  *
  * @param \Drupal\Core\Entity\EntityInterface $entity
diff --git a/core/modules/content_translation/content_translation.pages.inc b/core/modules/content_translation/content_translation.pages.inc
index aa1b1f3..c363233 100644
--- a/core/modules/content_translation/content_translation.pages.inc
+++ b/core/modules/content_translation/content_translation.pages.inc
@@ -86,6 +86,7 @@ function content_translation_overview(EntityInterface $entity) {
         // language we point the link to the translation form.
         if ($entity->access('update')) {
           $links['edit'] = isset($edit_links->links[$langcode]['href']) ? $edit_links->links[$langcode] : array('href' => $rel['edit-form']['path'], 'language' => $language);
+          $links['edit']['query']['content_translation_target'] = $langcode;
         }
         elseif (!$is_original && $controller->getTranslationAccess($entity, 'update')) {
           $links['edit'] = isset($translate_links->links[$langcode]['href']) ? $translate_links->links[$langcode] : array('href' => $translate_path, 'language' => $language);
@@ -187,14 +188,8 @@ function _content_translation_get_switch_links($path) {
  * @deprecated Use \Drupal\content_translation\Controller\ContentTranslationController::add()
  */
 function content_translation_add_page(EntityInterface $entity, Language $source = NULL, Language $target = NULL) {
-  $source = !empty($source) ? $source : $entity->language();
-  $target = !empty($target) ? $target : language(Language::TYPE_CONTENT);
-  // @todo Exploit the upcoming hook_entity_prepare() when available.
-  content_translation_prepare_translation($entity, $source, $target);
-  $form_state['langcode'] = $target->id;
-  $form_state['content_translation']['source'] = $source;
-  $form_state['content_translation']['target'] = $target;
-  $form_state['content_translation']['translation_form'] = !$entity->access('update');
+  $form_state = array();
+  content_translation_prepare_translation_form($entity, $source->id, $target->id, $form_state);
   return \Drupal::entityManager()->getForm($entity, 'default', $form_state);
 }
 
@@ -213,25 +208,50 @@ function content_translation_add_page(EntityInterface $entity, Language $source
  * @deprecated Use \Drupal\content_translation\Controller\ContentTranslationController::edit()
  */
 function content_translation_edit_page(EntityInterface $entity, Language $language = NULL) {
-  $language = !empty($language) ? $language : language(Language::TYPE_CONTENT);
-  $form_state['langcode'] = $language->id;
+  $form_state = array();
+  content_translation_prepare_translation_form($entity, FALSE, $language->id, $form_state);
   $form_state['content_translation']['translation_form'] = TRUE;
   return \Drupal::entityManager()->getForm($entity, 'default', $form_state);
 }
 
 /**
- * Populates target values with the source values.
+ * Form constructor for the translation deletion confirmation.
  *
- * @param \Drupal\Core\Entity\EntityInterface $entity
- *   The entitiy being translated.
- * @param \Drupal\Core\Language\Language $source
- *   The language to be used as source.
- * @param \Drupal\Core\Language\Language $target
- *   The language to be used as target.
+ * @deprecated Use \Drupal\content_translation\Form\ContentTranslationForm::deleteTranslation()
+ */
+function content_translation_delete_confirm(array $form, array $form_state, EntityInterface $entity, Language $language) {
+  $controller = content_translation_controller($entity->entityType());
+  $uri = $entity->uri('drupal:content-translation-overview');
+
+  return confirm_form(
+    $form,
+    t('Are you sure you want to delete the @language translation of %label?', array('@language' => $language->name, '%label' => $entity->label())),
+    $uri['path'],
+    t('This action cannot be undone.'),
+    t('Delete'),
+    t('Cancel')
+  );
+}
+
+/**
+ * Form submission handler for content_translation_delete_confirm().
  */
-function content_translation_prepare_translation(EntityInterface $entity, Language $source, Language $target) {
-  if ($entity instanceof ContentEntityInterface) {
-    $source_translation = $entity->getTranslation($source->id);
-    $entity->addTranslation($target->id, $source_translation->getPropertyValues());
+function content_translation_delete_confirm_submit(array $form, array &$form_state) {
+  list($entity, $language) = $form_state['build_info']['args'];
+  $controller = content_translation_controller($entity->entityType());
+
+  // Remove the translated values.
+  $entity->removeTranslation($language->id);
+  $entity->save();
+
+  // Remove any existing path alias for the removed translation.
+  // @todo This should be taken care of by the Path module.
+  if (\Drupal::moduleHandler()->moduleExists('path')) {
+    $uri = $entity->uri();
+    $conditions = array('source' => $uri['path'], 'langcode' => $language->id);
+    \Drupal::service('path.crud')->delete($conditions);
   }
+
+  $uri = $entity->uri('drupal:content-translation-overview');
+  $form_state['redirect'] = $uri['path'];
 }
diff --git a/core/modules/content_translation/lib/Drupal/content_translation/ContentTranslationController.php b/core/modules/content_translation/lib/Drupal/content_translation/ContentTranslationController.php
index e99c9b0..e98c89f 100644
--- a/core/modules/content_translation/lib/Drupal/content_translation/ContentTranslationController.php
+++ b/core/modules/content_translation/lib/Drupal/content_translation/ContentTranslationController.php
@@ -71,7 +71,7 @@ public function getTranslationAccess(EntityInterface $entity, $op) {
    * Implements ContentTranslationControllerInterface::getSourceLanguage().
    */
   public function getSourceLangcode(array $form_state) {
-    return isset($form_state['content_translation']['source']) ? $form_state['content_translation']['source']->id : FALSE;
+    return !empty($form_state['content_translation']['source']) ? $form_state['content_translation']['source'] : FALSE;
   }
 
   /**
diff --git a/core/modules/content_translation/lib/Drupal/content_translation/Tests/ContentTranslationUITest.php b/core/modules/content_translation/lib/Drupal/content_translation/Tests/ContentTranslationUITest.php
index 8a1b198..62a0e51 100644
--- a/core/modules/content_translation/lib/Drupal/content_translation/Tests/ContentTranslationUITest.php
+++ b/core/modules/content_translation/lib/Drupal/content_translation/Tests/ContentTranslationUITest.php
@@ -35,6 +35,7 @@
    */
   function testTranslationUI() {
     $this->doTestBasicTranslation();
+    $this->assertFormLanguage();
     $this->doTestTranslationOverview();
     $this->doTestOutdatedStatus();
     $this->doTestPublishedStatus();
@@ -218,6 +219,24 @@ protected function doTestAuthoringInfo() {
   }
 
   /**
+   * Tests the form language switch functionality.
+   */
+  protected function assertFormLanguage() {
+    $entity = $this->container
+      ->get('plugin.manager.entity')
+      ->getStorageController($this->entityType)
+      ->load($this->entityId);
+
+    $uri = $entity->uri('edit-form');
+    $message = 'The form language can be switched to @langcode through a query string parameter';
+    foreach ($entity->getTranslationLanguages() as $langcode => $language) {
+      $options = array('query' => array('content_translation_target' => $langcode));
+      $this->drupalGet($uri['path'], $options);
+      $this->assertRaw($entity->getTranslation($langcode)->{$this->fieldName}->value, format_string($message, array('@langcode' => $langcode)));
+    }
+  }
+
+  /**
    * Tests translation deletion.
    */
   protected function doTestTranslationDeletion() {
diff --git a/core/modules/content_translation/lib/Drupal/content_translation/Tests/ContentTranslationWorkflowsTest.php b/core/modules/content_translation/lib/Drupal/content_translation/Tests/ContentTranslationWorkflowsTest.php
index 0b3da77..ea36b69 100644
--- a/core/modules/content_translation/lib/Drupal/content_translation/Tests/ContentTranslationWorkflowsTest.php
+++ b/core/modules/content_translation/lib/Drupal/content_translation/Tests/ContentTranslationWorkflowsTest.php
@@ -127,7 +127,10 @@ protected function assertWorkflows(UserInterface $user, $expected_status) {
     // Check whether the user is allowed to access the entity form in edit mode.
     $uri = $this->entity->uri('edit-form');
     $edit_path = $uri['path'];
-    $options = array('language' => $languages[$default_langcode]);
+    $options = array(
+      'language' => $languages[$default_langcode],
+      'query' => array('content_translation_target' => $default_langcode),
+    );
     $this->drupalGet($edit_path, $options);
     $this->assertResponse($expected_status['edit'], format_string('The @user_label has the expected edit access.', $args));
 
@@ -166,7 +169,8 @@ protected function assertWorkflows(UserInterface $user, $expected_status) {
       if ($editor) {
         $this->clickLink('Edit', 2);
         // An editor should be pointed to the entity form in multilingual mode.
-        $this->assertUrl($edit_path, $options, 'The translation overview points to the edit form for editors when editing translations.');
+        $query = array('query' => array('content_translation_target' => $langcode));
+        $this->assertUrl($edit_path, $options + $query, 'The translation overview points to the edit form for editors when editing translations.');
       }
       else {
         $this->clickLink('Edit');
