diff --git a/includes/form.inc b/includes/form.inc
index 5058ffdf221d967cc1f3dd9698854d53f308adcd..366c6a11594a9d73fdcf808519a726066c973d97 100644
--- a/includes/form.inc
+++ b/includes/form.inc
@@ -188,9 +188,8 @@ function drupal_build_form($form_id, &$form_state) {
 
     if ($cacheable && !empty($form['#cache']) && empty($form['#no_cache'])) {
       // Caching is done past drupal_process_form so #process callbacks can
-      // set #cache. By not sending the form state, we avoid storing
-      // $form_state['storage'].
-      form_set_cache($form_build_id, $original_form, NULL);
+      // set #cache.
+      form_set_cache($form_build_id, $original_form, $form_state);
     }
   }
 
@@ -201,14 +200,14 @@ function drupal_build_form($form_id, &$form_state) {
   // the form will simply be re-rendered with the values still in its
   // fields.
   //
-  // If $form_state['storage'] or $form_state['rebuild'] have been
-  // set by any submit or validate handlers, however, we know that
-  // we're in a complex multi-part process of some sort and the form's
-  // workflow is NOT complete. We need to construct a fresh copy of
-  // the form, passing in the latest $form_state in addition to any
-  // other variables passed into drupal_get_form().
-
-  if (!empty($form_state['rebuild']) || !empty($form_state['storage'])) {
+  // If $form_state['storage'] or $form_state['rebuild'] has been set
+  // and the form has been submitted, we know that we're in a complex
+  // multi-part process of some sort and the form's workflow is NOT
+  // complete. We need to construct a fresh copy of the form, passing
+  // in the latest $form_state in addition to any other variables passed
+  // into drupal_get_form().
+
+  if ((!empty($form_state['storage']) || !empty($form_state['rebuild'])) && !empty($form_state['submitted']) && !form_get_errors()) {
     $form = drupal_rebuild_form($form_id, $form_state);
   }
 
diff --git a/modules/simpletest/tests/form.test b/modules/simpletest/tests/form.test
index 88b2614b9ca302e582bcc666b8cce96bab59fcb7..d787a850f9d7f9117557e22b700170910683f952 100644
--- a/modules/simpletest/tests/form.test
+++ b/modules/simpletest/tests/form.test
@@ -383,3 +383,69 @@ class FormAPITestCase extends DrupalWebTestCase {
   }
 
 }
+
+/**
+ * Test the form storage on a multistep form.
+ *
+ * The tested form puts data into the storage during the initial form
+ * construction. These tests verify that there are no duplicate form
+ * constructions, with and without manual form caching activiated. Furthermore
+ * when a validation error occurs, it makes sure that changed form element
+ * values aren't lost due to a wrong form rebuild.
+ */
+class FormsFormStorageTestCase extends DrupalWebTestCase {
+
+  function getInfo() {
+    return array(
+      'name'  => t('Multistep form using form storage'),
+      'description'  => t('Tests a multistep form using form storage and makes sure validation and caching works right.'),
+      'group' => t('Form API'),
+    );
+  }
+
+  function setUp() {
+    parent::setUp('form_test');
+  }
+
+  /**
+   * Tests using the form in a usual way.
+   */
+  function testForm() {
+    
+    $user = $this->drupalCreateUser(array('access content'));
+    $this->drupalLogin($user);
+
+    $this->drupalPost('form_test/form-storage', array('title' => 'new', 'value' => 'value_is_set'), 'Continue');
+    $this->assertText('Form constructions: 2', t('The form has been constructed two times till now.'));
+
+    $this->drupalPost(NULL, array(), 'Save');
+    $this->assertText('Form constructions: 3', t('The form has been constructed three times till now.'));
+    $this->assertText('Title: new', t('The form storage has stored the values.'));
+  }
+
+  /**
+   * Tests using the form with an activated #cache property.
+   */
+  function testFormCached() {
+    $user = $this->drupalCreateUser(array('access content'));
+    $this->drupalLogin($user);
+
+    $this->drupalPost('form_test/form-storage', array('title' => 'new', 'value' => 'value_is_set'), 'Continue', array('query' => 'cache=1'));
+    $this->assertText('Form constructions: 1', t('The form has been constructed one time till now.'));
+    
+    $this->drupalPost(NULL, array(), 'Save', array('query' => 'cache=1'));
+    $this->assertText('Form constructions: 2', t('The form has been constructed two times till now.'));
+    $this->assertText('Title: new', t('The form storage has stored the values.'));
+  }
+
+  /**
+   * Tests validation when form storage is used.
+   */
+  function testValidation() {
+    $user = $this->drupalCreateUser(array('access content'));
+    $this->drupalLogin($user);
+
+    $this->drupalPost('form_test/form-storage', array('title' => '', 'value' => 'value_is_set'), 'Continue');
+    $this->assertPattern('/value_is_set/', t("The input values have been kept."));
+  }
+}
diff --git a/modules/simpletest/tests/form_test.module b/modules/simpletest/tests/form_test.module
index dd91f6ebfda01b1f67bb0c6e639ebe22573c3437..afa08ba8965fc924cd4273a0cac0ddc7a406a229 100644
--- a/modules/simpletest/tests/form_test.module
+++ b/modules/simpletest/tests/form_test.module
@@ -58,6 +58,14 @@ function form_test_menu() {
     'type' => MENU_CALLBACK,
   );
 
+  $items['form_test/form-storage'] = array(
+    'title' => 'Form storage test',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('form_storage_test_form'),
+    'access arguments' => array('access content'),
+    'type' => MENU_CALLBACK,
+  );
+
   return $items;
 }
 
@@ -279,3 +287,81 @@ function form_test_mock_form($form_state) {
 function form_test_mock_form_submit($form, &$form_state) {
   variable_set('form_test_mock_submit', $form_state['values']['test_value']);
 }
+
+/**
+ * A multistep form for testing the form storage.
+ *
+ * It uses two steps for editing a virtual "thing". Any changes to it are saved
+ * in the form storage and have to be present during any step. By setting the
+ * request parameter "cache" the form can be tested with caching enabled, as
+ * it would be the case, if the form would contain some #ahah callbacks.
+ *
+ * @see form_storage_test_form_submit().
+ */
+function form_storage_test_form(&$form_state) {
+  // Initialize
+  if (!isset($form_state['storage'])) {
+    if (empty($form_state['input'])) {
+      $_SESSION['constructions'] = 0;
+    }
+    // Put the initial thing into the storage
+    $form_state['storage'] = array(
+      'thing' => array(
+        'title' => 'none',
+        'value' => '',
+      ),
+    );
+    $form_state['storage'] += array('step' => 1);
+  }
+
+  // Count how often the form is constructed
+  $_SESSION['constructions']++;
+
+  if ($form_state['storage']['step'] == 1) {
+    $form['title'] = array(
+      '#type' => 'textfield',
+      '#title' => 'title',
+      '#default_value' => $form_state['storage']['thing']['title'],
+      '#required' => TRUE,
+    );
+    $form['value'] = array(
+      '#type' => 'textfield',
+      '#title' => 'value',
+      '#default_value' => $form_state['storage']['thing']['value'],
+    );
+    $form['submit'] = array(
+      '#type' => 'submit',
+      '#value' => 'Continue',
+    );
+  }
+  else {
+    $form['content'] = array('#value' => 'This is the second step.');
+    $form['submit'] = array(
+      '#type' => 'submit',
+      '#value' => 'Save',
+    );
+  }
+
+  if (isset($_REQUEST['cache'])) {
+    // Manually activate caching, so we can test that the storage keeps working
+    // when it's enabled.
+    $form['#cache'] = TRUE;
+  }
+
+  return $form;
+}
+
+/**
+ * Multistep form submit callback.
+ */
+function form_storage_test_form_submit($form, &$form_state) {
+  if ($form_state['storage']['step'] == 1) {
+    $form_state['storage']['thing']['title'] = $form_state['values']['title'];
+    $form_state['storage']['thing']['value'] = $form_state['values']['value'];
+  }
+  else {
+    drupal_set_message("Title: ". check_plain($form_state['storage']['thing']['title']));
+  }
+  $form_state['storage']['step']++;
+  drupal_set_message("Form constructions: ". $_SESSION['constructions']);
+}