diff --git includes/form.inc includes/form.inc
index b4975e2..632d201 100644
--- includes/form.inc
+++ includes/form.inc
@@ -207,7 +207,10 @@ function drupal_get_form($form_id) {
  *     rebuild the form from cache when the original context may no longer be
  *     available:
  *     - args: An array of arguments to pass to the form builder.
- *     - file: An optional include file that contains the form and is
+ *     - files: An optional array defining include files that need to be loaded
+ *       for building the form. Each array entry may be the path to a file or
+ *       another array containing values for the parameters 'type', 'module' and
+ *       'name' as needed by module_load_include(). The files listed here are
  *       automatically loaded by form_get_cache(). Defaults to the current menu
  *       router item's 'file' definition, if existent.
  *   - rebuild: Normally, after the entire form processing is completed and
@@ -298,10 +301,10 @@ function drupal_build_form($form_id, &$form_state) {
       // rebuilt from cache on a different path (such as 'system/ajax'). See
       // form_get_cache().
       // $menu_get_item() is not available at installation time.
-      if (!isset($form_state['build_info']['file']) && !defined('MAINTENANCE_MODE')) {
+      if (!isset($form_state['build_info']['files']['menu']) && !defined('MAINTENANCE_MODE')) {
         $item = menu_get_item();
         if (!empty($item['include_file'])) {
-          $form_state['build_info']['file'] = $item['include_file'];
+          $form_state['build_info']['files']['menu'] = $item['include_file'];
         }
       }
 
@@ -474,10 +477,17 @@ function form_get_cache($form_build_id, &$form_state) {
         // Re-populate $form_state for subsequent rebuilds.
         $form_state = $cached->data + $form_state;
 
-        // If the original form is contained in an include file, load the file.
+        // If the original form is contained in include files, load the files.
         // See drupal_build_form().
-        if (!empty($form_state['build_info']['file']) && file_exists($form_state['build_info']['file'])) {
-          require_once DRUPAL_ROOT . '/' . $form_state['build_info']['file'];
+        $form_state['build_info'] += array('files' => array());
+        foreach ($form_state['build_info']['files'] as $file) {
+          if (is_array($file)) {
+            $file += array('type' => 'inc', 'name' => $file['module']);
+            module_load_include($file['type'], $file['module'], $file['name']);
+          }
+          elseif (file_exists($file)) {
+            require_once DRUPAL_ROOT . '/' . $file;
+          }
         }
       }
       return $form;
diff --git modules/simpletest/tests/form.test modules/simpletest/tests/form.test
index efaac4b..ad62bd8 100644
--- modules/simpletest/tests/form.test
+++ modules/simpletest/tests/form.test
@@ -1158,3 +1158,35 @@ class FormsArbitraryRebuildTestCase extends DrupalWebTestCase {
     $this->assertFieldByName('mail', 'bar@example.com', 'Entered mail address has been kept.');
   }
 }
+
+class FormsFileInclusionTestCase extends DrupalWebTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Form API file inclusion',
+      'description' => 'Tests form API file inclusion.',
+      'group' => 'Form API',
+    );
+  }
+
+  function setUp() {
+    parent::setUp('form_test');
+  }
+
+  /**
+   * Tests loading an include specified in hook_menu().
+   */
+  function testLoadMenuInclude() {
+    $this->drupalPostAJAX('form-test/load-include-menu', array(), array('op' => t('Save')), 'system/ajax', array(), array(), 'form-test-load-include-menu');
+    $this->assertText('Submit callback called.');
+  }
+
+  /**
+   * Tests loading a custom specified inlcude.
+   */
+  function testLoadCustomInclude() {
+    $this->drupalPost('form-test/load-include-custom', array(), t('Save'));
+    $this->assertText('Submit callback called.');
+  }
+
+}
diff --git modules/simpletest/tests/form_test.file.inc modules/simpletest/tests/form_test.file.inc
new file mode 100644
index 0000000..03419d2
--- /dev/null
+++ modules/simpletest/tests/form_test.file.inc
@@ -0,0 +1,40 @@
+<?php
+// $Id: module_test.module,v 1.5 2010/01/30 07:59:25 dries Exp $
+
+/**
+ * @file
+ * An include file to test loading it with the form API.
+ */
+
+/**
+ * Form constructor for testing FAPI file inclusion of the file specified in
+ * hook_menu().
+ */
+function form_test_load_include_menu($form, &$form_state) {
+  // Submit the form via AJAX. That way the FAPI has to care about including
+  // the file specified in hook_menu().
+  $form['button'] = array(
+    '#type' => 'submit',
+    '#value' => t('Save'),
+    '#submit' => array('form_test_load_include_submit'),
+    '#ajax' => array(
+      'callback' => 'form_test_load_include_menu_ajax',
+    ),
+  );
+  return $form;
+}
+
+/**
+ * Submit callback for the form API file inclusion test forms.
+ */
+function form_test_load_include_submit($form, $form_state) {
+  drupal_set_message('Submit callback called.');
+}
+
+/**
+ *  Ajax callback for the file inclusion via menu test. We don't need to return
+ *  anything as the messages are added automatically.
+ */
+function form_test_load_include_menu_ajax($form) {
+  return '';
+}
\ No newline at end of file
diff --git modules/simpletest/tests/form_test.info modules/simpletest/tests/form_test.info
index bc30d3c..5dcc285 100644
--- modules/simpletest/tests/form_test.info
+++ modules/simpletest/tests/form_test.info
@@ -5,4 +5,5 @@ package = Testing
 version = VERSION
 core = 7.x
 files[] = form_test.module
+files[] = form_test.file.inc
 hidden = TRUE
diff --git modules/simpletest/tests/form_test.module modules/simpletest/tests/form_test.module
index 065df57..f0607e3 100644
--- modules/simpletest/tests/form_test.module
+++ modules/simpletest/tests/form_test.module
@@ -153,6 +153,23 @@ function form_test_menu() {
     );
   }
 
+  $items['form-test/load-include-menu'] = array(
+    'title' => 'FAPI test loading includes',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('form_test_load_include_menu'),
+    'access callback' => TRUE,
+    'file' => 'form_test.file.inc',
+    'type' => MENU_CALLBACK,
+  );
+
+  $items['form-test/load-include-custom'] = array(
+    'title' => 'FAPI test loading includes',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('form_test_load_include_custom'),
+    'access callback' => TRUE,
+    'type' => MENU_CALLBACK,
+  );
+
   return $items;
 }
 
@@ -1169,3 +1186,20 @@ function form_test_two_instances() {
   $return['node_form_2'] = drupal_get_form('page_node_form', $node2);
   return $return;
 }
+
+/**
+ * Menu callback for testing custom form includes.
+ */
+function form_test_load_include_custom($form, &$form_state) {
+  $form['button'] = array(
+    '#type' => 'submit',
+    '#value' => t('Save'),
+    '#submit' => array('form_test_load_include_submit'),
+  );
+  // Specify the include file and enable form caching. That way the form is
+  // cached when it is submitted, but needs to find the specified submit handler
+  // in the include.
+  $form_state['build_info']['files'][] = array('module' => 'form_test', 'name' => 'form_test.file');
+  $form_state['cache'] = TRUE;
+  return $form;
+}
