diff --git includes/ajax.inc includes/ajax.inc
index 22d138b..393bd1a 100644
--- includes/ajax.inc
+++ includes/ajax.inc
@@ -199,6 +199,12 @@ function ajax_get_form() {
  * Menu callback for AJAX callbacks through the #ajax['callback'] Form API property.
  */
 function ajax_form_callback() {
+  // Find the triggering element, which was set up for us on the client side.
+  if (!empty($_POST['ajax_triggering_element'])) {
+    $triggering_element_path = $_POST['ajax_triggering_element'];
+    // Destroy field so it can't conflict in validation.
+    unset($_POST['ajax_triggering_element']);
+  }
   list($form, $form_state, $form_id, $form_build_id) = ajax_get_form();
 
   // Build, validate and if possible, submit the form.
@@ -208,10 +214,37 @@ function ajax_form_callback() {
   // drupal_process_form() set up.
   $form = drupal_rebuild_form($form_id, $form_state, $form_build_id);
 
-  // Get the callback function from the clicked button.
-  $ajax = $form_state['clicked_button']['#ajax'];
-  $callback = $ajax['callback'];
-  if (function_exists($callback)) {
+  // $triggering_element_path in a simple form might just be 'myselect', which
+  // would mean we should use the element $form['myselect']. However, if
+  // fieldsets are in use, it might be fieldset1/fieldset2/myselect in the case
+  // of a double-nested fieldset, so we would have to find our way to
+  // $form['fieldset1']['fieldset2']['myselect'].
+  // Here we break up the formpath and use it to traverse the form
+  // to find the element.
+  if (!empty($triggering_element_path)) {
+    if (!isset($form['#access']) || $form['#access']) {
+      $triggering_element = $form;
+      foreach (explode('/', $triggering_element_path) as $key) {
+        if (!empty($triggering_element[$key]) && (!isset($triggering_element[$key]['#access']) || $triggering_element[$key]['#access'])) {
+          $triggering_element = $triggering_element[$key];
+        }
+        else {
+          // We did not find the $triggering_element or do not have #access,
+          // so break out and do not provide it.
+          $triggering_element = NULL;
+          break;
+        }
+      }
+    }
+  }
+  if (empty($triggering_element)) {
+    $triggering_element = $form_state['clicked_button'];
+  }
+  // Now that we have the element, get a callback if there is one.
+  if (!empty($triggering_element)) {
+    $callback = $triggering_element['#ajax']['callback'];
+  }
+  if (!empty($callback) && function_exists($callback)) {
     $html = $callback($form, $form_state);
 
     // If the returned value is a string, assume it is HTML and create
@@ -305,6 +338,7 @@ function ajax_process_form($element) {
       'method'   => empty($element['#ajax']['method']) ? 'replace' : $element['#ajax']['method'],
       'progress' => empty($element['#ajax']['progress']) ? array('type' => 'throbber') : $element['#ajax']['progress'],
       'button'   => isset($element['#executes_submit_callback']) ? array($element['#name'] => $element['#value']) : FALSE,
+      'formPath' => implode('/', $element['#array_parents']),
     );
 
     // Convert a simple #ajax['progress'] type string into an array.
diff --git misc/ajax.js misc/ajax.js
index 0804992..1a6a77d 100644
--- misc/ajax.js
+++ misc/ajax.js
@@ -96,7 +96,7 @@ Drupal.ajax = function (base, element, element_settings) {
       type: 'bar',
       message: 'Please wait...'
     },
-    button: {},
+    button: {}
   };
 
   $.extend(this, defaults, element_settings);
@@ -183,6 +183,10 @@ Drupal.ajax.prototype.beforeSubmit = function (form_values, element, options) {
   // Disable the element that received the change.
   $(this.element).addClass('progress-disabled').attr('disabled', true);
 
+  // Server-side code needs to know what element triggered the call, so it can
+  // find the #ajax binding.
+  form_values.push({ name: 'ajax_triggering_element', value: this.formPath });
+
   // Insert progressbar or throbber.
   if (this.progress.type == 'bar') {
     var progressBar = new Drupal.progressBar('ajax-progress-' + this.element.id, eval(this.progress.update_callback), this.progress.method, eval(this.progress.error_callback));
