diff --git modules/file/file.field.inc modules/file/file.field.inc
index 31e4ce9..3a6e89c 100644
--- modules/file/file.field.inc
+++ modules/file/file.field.inc
@@ -645,11 +645,9 @@ function file_field_widget_process($element, &$form_state, $form) {
   // Adjust the AJAX settings so that on upload and remove of any individual
   // file, the entire group of file fields is updated together.
   if ($field['cardinality'] != 1) {
-    $new_path = preg_replace('/\/\d+\//', '/', $element['remove_button']['#ajax']['path'], 1);
     $new_wrapper = preg_replace('/-\d+-/', '-', $element['remove_button']['#ajax']['wrapper'], 1);
     foreach (element_children($element) as $key) {
       if (isset($element[$key]['#ajax'])) {
-        $element[$key]['#ajax']['path'] = $new_path;
         $element[$key]['#ajax']['wrapper'] = $new_wrapper;
       }
     }
diff --git modules/file/file.module modules/file/file.module
index c8b1fd0..5d35925 100644
--- modules/file/file.module
+++ modules/file/file.module
@@ -37,12 +37,6 @@ function file_help($path, $arg) {
 function file_menu() {
   $items = array();
 
-  $items['file/ajax'] = array(
-    'page callback' => 'file_ajax_upload',
-    'delivery callback' => 'ajax_deliver',
-    'access arguments' => array('access content'),
-    'type' => MENU_CALLBACK,
-  );
   $items['file/progress'] = array(
     'page callback' => 'file_ajax_progress',
     'delivery callback' => 'ajax_deliver',
@@ -198,73 +192,42 @@ function file_file_download($uri, $field_type = 'file') {
 }
 
 /**
- * Menu callback; Shared AJAX callback for file uploads and deletions.
+ * AJAX Callback for file uploads.
  *
- * This rebuilds the form element for a particular field item. As long as the
- * form processing is properly encapsulated in the widget element the form
- * should rebuild correctly using FAPI without the need for additional callbacks
- * or processing.
+ * Actual file handling is done by file_managed_file_submit(). This function
+ * just rebuilds the #managed_file element afterwards so that it can be
+ * replaced with an udpated version.
+ *
+ * @see file_managed_file_submit().
  */
-function file_ajax_upload() {
-  $form_parents = func_get_args();
-  $form_build_id = (string) array_pop($form_parents);
-
-  if (empty($_POST['form_build_id']) || $form_build_id != $_POST['form_build_id']) {
-    // Invalid request.
-    drupal_set_message(t('An unrecoverable error occurred. The uploaded file likely exceeded the maximum file size (@size) that this server supports.', array('@size' => format_size(file_upload_max_size()))), 'error');
-    $commands = array();
-    $commands[] = ajax_command_replace(NULL, theme('status_messages'));
-    return array('#type' => 'ajax', '#commands' => $commands, '#header' => FALSE);
+function file_ajax_upload($form, &$form_state) {
+  // Remove last element of the #parents array which is the remove button and
+  // then find the actual file element.
+  array_pop($form_state['clicked_button']['#parents']);
+  $element = $form;
+  foreach ($form_state['clicked_button']['#parents'] as $parent) {
+    $element = $element[$parent];
   }
 
-  list($form, $form_state, $form_id, $form_build_id) = ajax_get_form();
-
-  if (!$form) {
-    // Invalid form_build_id.
-    drupal_set_message(t('An unrecoverable error occurred. Use of this form has expired. Try reloading the page and submitting again.'), 'error');
-    $commands = array();
-    $commands[] = ajax_command_replace(NULL, theme('status_messages'));
-    return array('#type' => 'ajax', '#commands' => $commands, '#header' => FALSE);
-  }
-
-  // Get the current element and count the number of files.
-  $current_element = $form;
-  foreach ($form_parents as $parent) {
-    $current_element = $current_element[$parent];
-  }
-  $current_file_count = isset($current_element['#file_upload_delta']) ? $current_element['#file_upload_delta'] : 0;
-
-  // Build, validate and if possible, submit the form.
-  drupal_process_form($form_id, $form, $form_state);
-
-  // This call recreates the form relying solely on the form_state that the
-  // drupal_process_form() set up.
-  $form = drupal_rebuild_form($form_id, $form_state, $form);
-
-  // Retrieve the element to be rendered.
-  foreach ($form_parents as $parent) {
-    $form = $form[$parent];
-  }
-
-  // Add the special AJAX class if a new file was added.
-  if (isset($form['#file_upload_delta']) && $current_file_count < $form['#file_upload_delta']) {
-    $form[$current_file_count]['#attributes']['class'][] = 'ajax-new-content';
-  }
-  // Otherwise just add the new content class on a placeholder.
-  else {
-    $form['#suffix'] .= '<span class="ajax-new-content"></span>';
-  }
-
-  $output = theme('status_messages') . drupal_render($form);
-  $js = drupal_add_js();
-  $settings = call_user_func_array('array_merge_recursive', $js['settings']['data']);
-
   $commands = array();
-  $commands[] = ajax_command_replace(NULL, $output, $settings);
+  $commands[] = ajax_command_replace(NULL, drupal_render($element));
   return array('#type' => 'ajax', '#commands' => $commands, '#header' => FALSE);
 }
 
 /**
+ * AJAX Callback for remove file button.
+ *
+ * Actual removal of the file is handled by file_managed_file_remove_submit().
+ * This function just rebuilds the #managed_file element afterwards so that it
+ * can be replaced with an updated version.
+ *
+ * @see file_managed_file_remove_submit().
+ */
+function file_ajax_remove($form, &$form_state) {
+  return file_ajax_upload($form, &$form_state);
+}
+
+/**
  * Menu callback for upload progress.
  *
  * @param $key
@@ -349,7 +312,7 @@ function file_managed_file_process($element, &$form_state, $form) {
   $element['#tree'] = TRUE;
 
   $ajax_settings = array(
-    'path' => 'file/ajax/' . implode('/', $element['#parents']) . '/' . $form['form_build_id']['#value'],
+    'callback' => 'file_ajax_upload',
     'wrapper' => $element['#id'] . '-ajax-wrapper',
     'method' => 'replace',
     'effect' => 'fade',
@@ -359,7 +322,7 @@ function file_managed_file_process($element, &$form_state, $form) {
     ),
   );
 
-  // Set up the buttons first since we need to check if they were clicked.
+  // Add Upload/Remove buttons.
   $element['upload_button'] = array(
     '#name' => implode('_', $element['#parents']) . '_upload_button',
     '#type' => 'submit',
@@ -371,6 +334,7 @@ function file_managed_file_process($element, &$form_state, $form) {
     '#weight' => -5,
   );
 
+  $ajax_settings['callback'] = 'file_ajax_remove';
   $ajax_settings['progress']['type'] ? $ajax_settings['progress']['type'] == 'bar' : 'throbber';
   $ajax_settings['progress']['message'] = NULL;
   $ajax_settings['effect'] = 'none';
@@ -379,27 +343,12 @@ function file_managed_file_process($element, &$form_state, $form) {
     '#type' => 'submit',
     '#value' => t('Remove'),
     '#validate' => array(),
-    '#submit' => array('file_managed_file_submit'),
+    '#submit' => array('file_managed_file_remove_submit'),
     '#limit_validation_errors' => array($element['#parents']),
     '#ajax' => $ajax_settings,
     '#weight' => -5,
   );
 
-  // @todo It is not good to call these private functions. This should be
-  //   refactored so that the file deletion happens during a submit handler,
-  //   and form changes affected by that (such as toggling the upload and remove
-  //   buttons) happens during the 2nd run of this function that is triggered by
-  //   a form rebuild: http://drupal.org/node/736298.
-  if (_form_button_was_clicked($element['remove_button'], $form_state) || _form_element_triggered_scripted_submission($element['remove_button'], $form_state)) {
-    // If it's a temporary file we can safely remove it immediately, otherwise
-    // it's up to the implementing module to clean up files that are in use.
-    if ($element['#file'] && $element['#file']->status == 0) {
-      file_delete($element['#file']);
-    }
-    $element['#file'] = FALSE;
-    $fid = 0;
-  }
-
   // Set access on the buttons.
   $element['upload_button']['#access'] = empty($fid);
   $element['remove_button']['#access'] = !empty($fid);
@@ -566,12 +515,41 @@ function file_managed_file_validate(&$element, &$form_state) {
 }
 
 /**
- * Submit handler for non-JavaScript uploads.
+ * Submit handler for upload button on #managed_file elements.
  */
 function file_managed_file_submit($form, &$form_state) {
-  // Do not redirect and leave the page after uploading a file. This keeps
-  // all the current form values in place. The file is saved by the
-  // #value_callback on the form element.
+  // Get the current element and count the number of files.
+  $clicked_button = array_pop($form_state['triggering_element']['#parents']);
+  $current_element = $form;
+  foreach ($form_state['triggering_element']['#parents'] as $parent) {
+    $current_element = $current_element[$parent];
+  }
+
+  // Save the uploaded file.
+  $current_element['#file'] = file_managed_file_save_upload($current_element);
+
+  $form_state['redirect'] = FALSE;
+}
+
+/**
+ * Submit handler for remove button on #managed_file elements.
+ */
+function file_managed_file_remove_submit($form, &$form_state) {
+  $clicked_button = $form_state['triggering_element'];
+  array_pop($clicked_button['#parents']);
+  $element = $form;
+  foreach ($clicked_button['#parents'] as $parent) {
+    $element = $element[$parent];
+  }
+
+  // If it's a temporary file we can safely remove it immediately, otherwise
+  // it's up to the implementing module to clean up files that are in use.
+  if ($element['#file'] && $element['#file']->status == 0) {
+    file_delete($element['#file']);
+  }
+
+  form_set_value($element, NULL, $form_state);
+
   $form_state['redirect'] = FALSE;
 }
 
