diff --git a/core/modules/field/field.module b/core/modules/field/field.module
index 3435e73..8ab7c20 100644
--- a/core/modules/field/field.module
+++ b/core/modules/field/field.module
@@ -461,6 +461,14 @@ function field_entity_field_info($entity_type) {
 }
 
 /**
+ * Implements hook_field_widget_info_alter().
+ */
+function field_field_widget_info_alter(&$info) {
+  // Add the Hidden widget to all field types.
+  $info['hidden']['field_types'] = array_keys(field_info_field_types());
+}
+
+/**
  * Applies language fallback rules to the fields attached to the given entity.
  *
  * Core language fallback rules simply check if fields have a field translation
diff --git a/core/modules/field/lib/Drupal/field/Plugin/Type/LegacyDiscoveryDecorator.php b/core/modules/field/lib/Drupal/field/Plugin/Type/LegacyDiscoveryDecorator.php
index 43aad82..1f94d7c 100644
--- a/core/modules/field/lib/Drupal/field/Plugin/Type/LegacyDiscoveryDecorator.php
+++ b/core/modules/field/lib/Drupal/field/Plugin/Type/LegacyDiscoveryDecorator.php
@@ -67,6 +67,9 @@ public function getDefinitions() {
           unset($definition['behaviors']['default value']);
         }
 
+        // Legacy widgets also need a plugin id.
+        $definition['id'] = $plugin_id;
+
         $definitions[$plugin_id] = $definition;
       }
     }
diff --git a/core/modules/field/lib/Drupal/field/Plugin/field/widget/HiddenWidget.php b/core/modules/field/lib/Drupal/field/Plugin/field/widget/HiddenWidget.php
new file mode 100644
index 0000000..4054838
--- /dev/null
+++ b/core/modules/field/lib/Drupal/field/Plugin/field/widget/HiddenWidget.php
@@ -0,0 +1,34 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\field\Plugin\field\widget\HiddenWidget.
+ */
+
+namespace Drupal\field\Plugin\field\widget;
+
+use Drupal\Component\Annotation\Plugin;
+use Drupal\Core\Annotation\Translation;
+use Drupal\field\Plugin\Type\Widget\WidgetBase;
+
+/**
+ * Plugin implementation of the 'Hidden' widget.
+ *
+ * @Plugin(
+ *   id = "hidden",
+ *   module = "field",
+ *   label = @Translation("- Hidden -"),
+ *   multiple_values = TRUE,
+ *   weight = 50
+ * )
+ */
+class HiddenWidget extends WidgetBase {
+
+  /**
+   * Implements Drupal\field\Plugin\Type\Widget\WidgetInterface::formElement().
+   */
+  public function formElement(array $items, $delta, array $element, $langcode, array &$form, array &$form_state) {
+    // The purpose of this widget is to be hidden, so nothing to do here.
+    return array();
+  }
+}
diff --git a/core/modules/field/lib/Drupal/field/Tests/FormTest.php b/core/modules/field/lib/Drupal/field/Tests/FormTest.php
index fcda223..b0a830d 100644
--- a/core/modules/field/lib/Drupal/field/Tests/FormTest.php
+++ b/core/modules/field/lib/Drupal/field/Tests/FormTest.php
@@ -577,4 +577,63 @@ function testNestedFieldForm() {
     $this->assertFieldValues($entity_1, 'field_unlimited', LANGUAGE_NOT_SPECIFIED, array(3, 2));
     $this->assertFieldValues($entity_2, 'field_unlimited', LANGUAGE_NOT_SPECIFIED, array(13, 14, 15));
   }
+
+  /**
+   * Tests the Hidden widget.
+   */
+  function testFieldFormHiddenWidget() {
+    $this->field = $this->field_single;
+    $this->field_name = $this->field['field_name'];
+    $this->instance['field_name'] = $this->field_name;
+    $this->instance['widget']['type'] = 'hidden';
+    $this->instance['default_value'] = array(0 => array('value' => 99));
+    field_create_field($this->field);
+    field_create_instance($this->instance);
+    $langcode = LANGUAGE_NOT_SPECIFIED;
+
+    // Display the entity creation form.
+    $this->drupalGet('test-entity/add/test_bundle');
+
+    // Create an entity and test that the default value is assigned correctly to
+    // the field that uses the hidden widget.
+    $this->assertNoField("{$this->field_name}[$langcode][0][value]", 'The hidden widget is not displayed');
+    $this->drupalPost(NULL, array(), t('Save'));
+    preg_match('|test-entity/manage/(\d+)/edit|', $this->url, $match);
+    $id = $match[1];
+    $this->assertRaw(t('test_entity @id has been created.', array('@id' => $id)), 'Entity was created');
+    $entity = field_test_entity_test_load($id);
+    $this->assertEqual($entity->{$this->field_name}[$langcode][0]['value'], 99, 'Default value was saved');
+
+    // Update the instance to remove the default value and switch to the
+    // default widget.
+    $this->instance['default_value'] = NULL;
+    $this->instance['widget']['type'] = 'test_field_widget';
+    field_update_instance($this->instance);
+
+    // Display edit form.
+    $this->drupalGet('test-entity/manage/' . $id . '/edit');
+    $this->assertFieldByName("{$this->field_name}[$langcode][0][value]", 99, 'Widget is displayed with the correct default value');
+
+    // Update the entity.
+    $value = mt_rand(1, 127);
+    $edit = array("{$this->field_name}[$langcode][0][value]" => $value);
+    $this->drupalPost(NULL, $edit, t('Save'));
+    $this->assertRaw(t('test_entity @id has been updated.', array('@id' => $id)), 'Entity was updated');
+    entity_get_controller('test_entity')->resetCache(array($id));
+    $entity = field_test_entity_test_load($id);
+    $this->assertEqual($entity->{$this->field_name}[$langcode][0]['value'], $value, 'Field value was updated');
+
+    // Update the instance and switch to the Hidden widget again.
+    $this->instance['widget']['type'] = 'hidden';
+    field_update_instance($this->instance);
+
+    // Create a new revision.
+    $edit = array('revision' => TRUE);
+    $this->drupalPost('test-entity/manage/' . $id . '/edit', $edit, t('Save'));
+
+    // Check that the expected value has been carried over to the new revision.
+    entity_get_controller('test_entity')->resetCache(array($id));
+    $entity = field_test_entity_test_load($id);
+    $this->assertEqual($entity->{$this->field_name}[$langcode][0]['value'], $value, 'New revision has the expected value for the field with the Hidden widget');
+  }
 }
diff --git a/core/modules/field_ui/field_ui.admin.inc b/core/modules/field_ui/field_ui.admin.inc
index 566959b..df38d93 100644
--- a/core/modules/field_ui/field_ui.admin.inc
+++ b/core/modules/field_ui/field_ui.admin.inc
@@ -691,6 +691,10 @@ function field_ui_widget_type_form_submit($form, &$form_state) {
   try {
     field_update_instance($instance);
     drupal_set_message(t('Changed the widget for field %label.', array('%label' => $instance['label'])));
+
+    if ($instance['required'] && empty($instance['default_value']) && empty($instance['default_value_function']) && $instance['widget']['type'] == 'field_hidden') {
+      drupal_set_message(t('Field %label is required and uses the "hidden" widget. You might want to configure a default value.', array('%label' => $instance['label'])), 'warning');
+    }
   }
   catch (Exception $e) {
     drupal_set_message(t('There was a problem changing the widget for field %label.', array('%label' => $instance['label'])), 'error');
@@ -934,6 +938,19 @@ function field_ui_default_value_widget($field, $instance, &$form, &$form_state)
   $instance['required'] = FALSE;
   $instance['description'] = '';
 
+  // Adjust the instance definition to use the default widget of this field type
+  // instead of the hidden widget.
+  if ($instance['widget']['type'] == 'field_hidden') {
+    $field_type = field_info_field_types($field['type']);
+    $default_widget = field_info_widget_types($field_type['default_widget']);
+
+    $instance['widget'] = array(
+      'type' => $default_widget['id'],
+      'settings' => $default_widget['settings'],
+      'weight' => 0,
+    );
+  }
+
   // Insert the widget. Since we do not use the "official" instance definition,
   // the whole flow cannot use field_invoke_method().
   $items = (array) $instance['default_value'];
@@ -1013,6 +1030,10 @@ function field_ui_field_edit_form_submit($form, &$form_state) {
 
   drupal_set_message(t('Saved %label configuration.', array('%label' => $instance['label'])));
 
+  if ($instance['required'] && empty($instance['default_value']) && empty($instance['default_value_function']) && $instance['widget']['type'] == 'field_hidden') {
+    drupal_set_message(t('Field %label is required and uses the "hidden" widget. You might want to configure a default value.', array('%label' => $instance['label'])), 'warning');
+  }
+
   $form_state['redirect'] = field_ui_next_destination($instance['entity_type'], $instance['bundle']);
 }
 
