diff --git a/core/lib/Drupal/Core/Entity/EntityManager.php b/core/lib/Drupal/Core/Entity/EntityManager.php
index ba644be..3fc38fd 100644
--- a/core/lib/Drupal/Core/Entity/EntityManager.php
+++ b/core/lib/Drupal/Core/Entity/EntityManager.php
@@ -386,7 +386,7 @@ protected function buildBaseFieldDefinitions($entity_type_id) {
         foreach ($module_definitions as $field_name => $definition) {
           // @todo Remove this check once FieldDefinitionInterface exposes a
           //  proper provider setter. See https://drupal.org/node/2225961.
-          if ($definition instanceof FieldDefinition) {
+          if ($definition instanceof FieldDefinition && $definition->getProvider() == NULL) {
             $definition->setProvider($module);
           }
           $base_field_definitions[$field_name] = $definition;
diff --git a/core/lib/Drupal/Core/Field/FieldDefinition.php b/core/lib/Drupal/Core/Field/FieldDefinition.php
index 828ee70..1c3496a 100644
--- a/core/lib/Drupal/Core/Field/FieldDefinition.php
+++ b/core/lib/Drupal/Core/Field/FieldDefinition.php
@@ -183,7 +183,7 @@ public function setSetting($setting_name, $value) {
    * {@inheritdoc}
    */
   public function getProvider() {
-    return $this->definition['provider'];
+    return isset($this->definition['provider']) ? $this->definition['provider'] : NULL;
   }
 
   /**
diff --git a/core/modules/contact/src/Entity/Message.php b/core/modules/contact/src/Entity/Message.php
index f2c05fc..04e292a 100644
--- a/core/modules/contact/src/Entity/Message.php
+++ b/core/modules/contact/src/Entity/Message.php
@@ -26,7 +26,8 @@
  *     }
  *   },
  *   entity_keys = {
- *     "bundle" = "category"
+ *     "bundle" = "category",
+ *     "uuid" = "uuid"
  *   },
  *   bundle_entity_type = "contact_category",
  *   fieldable = TRUE,
@@ -40,20 +41,6 @@ class Message extends ContentEntityBase implements MessageInterface {
   /**
    * {@inheritdoc}
    */
-  public function id() {
-    return NULL;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function uuid() {
-    return NULL;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
   public function isPersonal() {
     return $this->bundle() == 'personal';
   }
@@ -154,6 +141,15 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
       ->setSettings(array('target_type' => 'contact_category'))
       ->setRequired(TRUE);
 
+    $fields['uuid'] = FieldDefinition::create('uuid')
+      ->setLabel(t('UUID'))
+      ->setDescription(t('The message UUID.'))
+      ->setReadOnly(TRUE);
+
+    $fields['langcode'] = FieldDefinition::create('language')
+      ->setLabel(t('Language code'))
+      ->setDescription(t('The comment language code.'));
+
     $fields['name'] = FieldDefinition::create('string')
       ->setLabel(t("The sender's name"))
       ->setDescription(t('The name of the person that is sending the contact message.'));
diff --git a/core/modules/contact/src/MessageForm.php b/core/modules/contact/src/MessageForm.php
index 5915fd0..0b5a37c 100644
--- a/core/modules/contact/src/MessageForm.php
+++ b/core/modules/contact/src/MessageForm.php
@@ -11,6 +11,8 @@
 use Drupal\Core\Entity\ContentEntityForm;
 use Drupal\Core\Entity\EntityManagerInterface;
 use Drupal\Core\Flood\FloodInterface;
+use Drupal\Core\Language\Language;
+use Drupal\Core\Language\LanguageInterface;
 use Drupal\user\UserInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
@@ -74,6 +76,15 @@ public function form(array $form, array &$form_state) {
       $form['preview']['message'] = entity_view($message, 'full');
     }
 
+    $language_configuration = \Drupal::moduleHandler()->invoke('language', 'get_default_configuration', array('contact_message', $message->getCategory()->id()));
+    $form['langcode'] = array(
+      '#title' => t('Language'),
+      '#type' => 'language_select',
+      '#default_value' => $message->getUntranslated()->language()->id,
+      '#languages' => Language::STATE_ALL,
+      '#access' => isset($language_configuration['language_show']) && $language_configuration['language_show'],
+    );
+
     $form['name'] = array(
       '#type' => 'textfield',
       '#title' => t('Your name'),
@@ -254,5 +265,26 @@ public function save(array $form, array &$form_state) {
     else {
       $form_state['redirect_route']['route_name'] = '<front>';
     }
+    // Save the message. In core this is a no-op but should contrib wish to
+    // implement message storage, this will make the task of swapping in a real
+    // storage controller straight-forward.
+    $message->save();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function init(array &$form_state) {
+    $message = $this->entity;
+
+    // Make the message inherit the current content language unless specifically
+    // set.
+    if ($message->isNew() && !$message->langcode->value) {
+      $language_content = \Drupal::languageManager()->getCurrentLanguage(LanguageInterface::TYPE_CONTENT);
+      $message->langcode->value = $language_content->id;
+    }
+
+    parent::init($form_state);
   }
+
 }
diff --git a/core/modules/contact/src/Tests/ContactStorageTest.php b/core/modules/contact/src/Tests/ContactStorageTest.php
new file mode 100644
index 0000000..c5784a7
--- /dev/null
+++ b/core/modules/contact/src/Tests/ContactStorageTest.php
@@ -0,0 +1,73 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\contact\Tests\ContactStorageTest.
+ */
+
+namespace Drupal\contact\Tests;
+
+use Drupal\contact\Entity\Message;
+
+/**
+ * Tests storing contact messages.
+ */
+class ContactStorageTest extends ContactSitewideTest {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = array(
+    'text',
+    'contact',
+    'field_ui',
+    'contact_storage_test',
+  );
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Contact Storage',
+      'description' => 'Tests that contact messages can be stored.',
+      'group' => 'Contact',
+    );
+  }
+
+  /**
+   * Tests configuration options and the site-wide contact form.
+   */
+  public function testContactStorage() {
+    // Create and login administrative user.
+    $admin_user = $this->drupalCreateUser(array(
+      'access site-wide contact form',
+      'administer contact forms',
+      'administer users',
+      'administer account settings',
+      'administer contact_message fields',
+    ));
+    $this->drupalLogin($admin_user);
+    // Create first valid category.
+    $mail = 'simpletest@example.com';
+    $this->addCategory($id = drupal_strtolower($this->randomName(16)), $label = $this->randomName(16), implode(',', array($mail)), '', TRUE);
+    $this->assertRaw(t('Category %label has been added.', array('%label' => $label)));
+
+    // Ensure that anonymous can submit site-wide contact form.
+    user_role_grant_permissions(DRUPAL_ANONYMOUS_RID, array('access site-wide contact form'));
+    $this->drupalLogout();
+    $this->drupalGet('contact');
+    $this->assertText(t('Your email address'));
+    $this->assertNoText(t('Category'));
+    $this->submitContact($name = $this->randomName(16), $mail, $subject = $this->randomName(16), $id, $message = $this->randomName(64));
+    $this->assertText(t('Your message has been sent.'));
+
+    $messages = Message::loadMultiple();
+    /** @var \Drupal\contact\Entity\Message $message */
+    $message = reset($messages);
+    $this->assertEqual($message->getCategory()->id(), $id);
+    $this->assertEqual($message->getSenderName(), $name);
+    $this->assertEqual($message->getSubject(), $subject);
+    $this->assertEqual($message->getSenderMail(), $mail);
+  }
+
+}
diff --git a/core/modules/contact/tests/modules/contact_storage_test/contact_storage_test.info.yml b/core/modules/contact/tests/modules/contact_storage_test/contact_storage_test.info.yml
new file mode 100644
index 0000000..f590c3f
--- /dev/null
+++ b/core/modules/contact/tests/modules/contact_storage_test/contact_storage_test.info.yml
@@ -0,0 +1,9 @@
+name: 'Contact test storage'
+type: module
+description: 'Tests that contact messages can be stored.'
+package: Testing
+version: VERSION
+core: 8.x
+dependencies:
+  - contact
+  - user
diff --git a/core/modules/contact/tests/modules/contact_storage_test/contact_storage_test.install b/core/modules/contact/tests/modules/contact_storage_test/contact_storage_test.install
new file mode 100644
index 0000000..bcbe5df
--- /dev/null
+++ b/core/modules/contact/tests/modules/contact_storage_test/contact_storage_test.install
@@ -0,0 +1,24 @@
+<?php
+
+/**
+ * @file
+ * Contains install and update hooks.
+ */
+
+/**
+ * Implements hook_install().
+ */
+function contact_storage_test_install() {
+  // ModuleHandler won't create the schema automatically because Message entity
+  // belongs to contact.module.
+  // @todo Remove this when https://www.drupal.org/node/1498720 is in.
+  $entity_manager = \Drupal::entityManager();
+  $schema = \Drupal::database()->schema();
+  $entity_type = $entity_manager->getDefinition('contact_message');
+  $storage = $entity_manager->getStorage($entity_type->id());
+  foreach ($storage->getSchema() as $table_name => $table_schema) {
+    if (!$schema->tableExists($table_name)) {
+      $schema->createTable($table_name, $table_schema);
+    }
+  }
+}
diff --git a/core/modules/contact/tests/modules/contact_storage_test/contact_storage_test.module b/core/modules/contact/tests/modules/contact_storage_test/contact_storage_test.module
new file mode 100644
index 0000000..88f4e2e
--- /dev/null
+++ b/core/modules/contact/tests/modules/contact_storage_test/contact_storage_test.module
@@ -0,0 +1,43 @@
+<?php
+
+/**
+ * @file
+ * Contains custom contact message functionality for ContactStorageTest.
+ */
+
+use Drupal\Core\Field\FieldDefinition;
+
+/**
+ * Implements hook_entity_base_field_info().
+ */
+function contact_storage_test_entity_base_field_info(\Drupal\Core\Entity\EntityTypeInterface $entity_type) {
+  if ($entity_type->id() == 'contact_message') {
+    $fields = array();
+    $fields['id'] = FieldDefinition::create('integer')
+      ->setLabel(t('Message ID'))
+      ->setDescription(t('The message ID.'))
+      ->setReadOnly(TRUE)
+      // Explicitly set this to 'contact' so that
+      // ContentEntityDatabaseStorage::usesDedicatedTable() doesn't attempt to
+      // put the ID in a dedicated table.
+      ->setProvider('contact')
+      ->setSetting('unsigned', TRUE);
+
+    return $fields;
+  }
+}
+
+
+/**
+ * Implements hook_entity_type_alter().
+ */
+function contact_storage_test_entity_type_alter(array &$entity_types) {
+  /** @var $entity_types \Drupal\Core\Entity\EntityTypeInterface[] */
+  // Set the controller class for nodes to an alternate implementation of the
+  // Drupal\Core\Entity\EntityStorageInterface interface.
+  $entity_types['contact_message']->setStorageClass('\Drupal\Core\Entity\ContentEntityDatabaseStorage');
+  $keys = $entity_types['contact_message']->getKeys();
+  $keys['id'] = 'id';
+  $entity_types['contact_message']->set('entity_keys', $keys);
+  $entity_types['contact_message']->set('base_table', 'contact_message');
+}
