diff --git a/src/metabase/lib/drill_thru/common.cljc b/src/metabase/lib/drill_thru/common.cljc
index 2bcfc6803d00ae2e65dcf402c218e7878f28f72f..2ef8cd8bbe7a8da40cf2065c9c5d01a80d59ee08 100644
--- a/src/metabase/lib/drill_thru/common.cljc
+++ b/src/metabase/lib/drill_thru/common.cljc
@@ -2,6 +2,7 @@
   (:require
    [metabase.lib.hierarchy :as lib.hierarchy]
    [metabase.lib.metadata.calculation :as lib.metadata.calculation]
+   [metabase.lib.underlying :as lib.underlying]
    [metabase.lib.util :as lib.util]))
 
 (defn mbql-stage?
@@ -46,3 +47,35 @@
   "Convert a drill value to a JS value"
   [value]
   (if (= value :null) nil value))
+
+(defn- has-source-or-underyling-source-fn
+  [source]
+  (fn has-source?
+    ([column]
+     (= (:lib/source column) source))
+    ([query column]
+     (and
+      (seq column)
+      (or (has-source? column)
+          (has-source? (lib.underlying/top-level-column query column)))))))
+
+(def aggregation-sourced?
+  "Does column or top-level-column have :source/aggregations?"
+  (has-source-or-underyling-source-fn :source/aggregations))
+
+(def breakout-sourced?
+  "Does column or top-level-column have :source/breakouts?"
+  (has-source-or-underyling-source-fn :source/breakouts))
+
+(defn strictly-underyling-aggregation?
+  "Does the top-level-column for `column` in `query` have :source/aggregations?"
+  [query column]
+  (and (not (aggregation-sourced? column))
+       (aggregation-sourced? query column)))
+
+(defn dimensions-from-breakout-columns
+  "Convert `row` data into dimensions for `column`s that come from an aggregation in a previous stage."
+  [query column row]
+  (when (strictly-underyling-aggregation? query column)
+    (not-empty (filterv #(breakout-sourced? query (:column %))
+                        row))))
diff --git a/src/metabase/lib/drill_thru/zoom_in_timeseries.cljc b/src/metabase/lib/drill_thru/zoom_in_timeseries.cljc
index 3a4f9c549a54bff31be06d9271a1e2462cda20e6..7644a107e10efcfed7f4716999aacbbef4b92085 100644
--- a/src/metabase/lib/drill_thru/zoom_in_timeseries.cljc
+++ b/src/metabase/lib/drill_thru/zoom_in_timeseries.cljc
@@ -14,7 +14,8 @@
   - `dimensions` have a date or datetime column with `year`, `quarter`, `month`, `week`, `day`, `hour` temporal unit.
     For other units, or when there is no temporal bucketing, this drill cannot be applied. Changing `hour` to `minute`
     ends the sequence for datetime columns (`week` to `day` for date columns). Only the first matching column would be
-    used in query transformation.
+    used in query transformation. If `dimensions` are not provided, `row` data will instead be used to try to find a
+    `matching-breakout-dimension`.
 
   - `displayInfo` returns `displayName` with `See this {0} by {1}` string using the current and the next available
     temporal unit.
@@ -45,6 +46,7 @@
    [metabase.lib.schema.drill-thru :as lib.schema.drill-thru]
    [metabase.lib.schema.temporal-bucketing :as lib.schema.temporal-bucketing]
    [metabase.lib.temporal-bucket :as lib.temporal-bucket]
+   [metabase.lib.underlying :as lib.underlying]
    [metabase.lib.util :as lib.util]
    [metabase.util.i18n :as i18n]
    [metabase.util.malli :as mu]))
@@ -62,14 +64,22 @@
   [query        :- ::lib.schema/query
    stage-number :- :int
    dimensions   :- [:sequential ::lib.schema.drill-thru/context.row.value]]
-  (first (for [breakout (lib.breakout/breakouts query stage-number)
-               :when (and (lib.util/clause-of-type? breakout :field)
-                          (lib.temporal-bucket/temporal-bucket breakout))
+  (first (for [[breakout-ref breakout-col] (map vector
+                                                (lib.breakout/breakouts query stage-number)
+                                                (lib.breakout/breakouts-metadata query stage-number))
+               :when (and (lib.util/clause-of-type? breakout-ref :field)
+                          (lib.temporal-bucket/temporal-bucket breakout-ref))
                {:keys [column] :as dimension} dimensions
-               :when (and (lib.equality/find-matching-column breakout [column])
-                          (= (lib.temporal-bucket/temporal-bucket breakout)
-                             (lib.temporal-bucket/temporal-bucket column)))]
-           (assoc dimension :column-ref breakout))))
+               :when (and (lib.equality/find-matching-column breakout-ref [column])
+                          (= (lib.temporal-bucket/raw-temporal-bucket breakout-ref)
+                             (or (lib.temporal-bucket/raw-temporal-bucket column)
+                                 ;; If query is multi-stage and column comes from a call
+                                 ;; to [[lib.calculation/returned-columns]], then it may have an
+                                 ;; :inherited-temporal-unit instead of a :temporal-unit.
+                                 (:inherited-temporal-unit column))))]
+           ;; If stage-number is not -1, then the column from the input dimension will be from the last stage,
+           ;; whereas breakout-col will be the corresponding breakout column from [[lib.underlying/top-level-stage]].
+           (assoc dimension :column breakout-col :column-ref breakout-ref))))
 
 (mu/defn- next-breakout-unit :- [:maybe ::lib.schema.drill-thru/drill-thru.zoom-in.timeseries.next-unit]
   [query :- ::lib.schema/query
@@ -96,27 +106,34 @@
   For example: The month of a year, days or weeks of a quarter, smaller lat/long regions, etc.
 
   This is different from the `:drill-thru/zoom` type, which is for showing the details of a single object."
-  [query                              :- ::lib.schema/query
-   stage-number                       :- :int
-   {:keys [dimensions], :as _context} :- ::lib.schema.drill-thru/context]
-  (when (and (lib.drill-thru.common/mbql-stage? query stage-number)
-             (not-empty dimensions))
-    (when-let [{:keys [value column-ref], :as dimension} (matching-breakout-dimension query stage-number dimensions)]
-      (when value
-        (when-let [next-unit (next-breakout-unit query stage-number column-ref)]
-          {:lib/type     :metabase.lib.drill-thru/drill-thru
-           :display-name (describe-next-unit next-unit)
-           :type         :drill-thru/zoom-in.timeseries
-           :dimension    dimension
-           :next-unit    next-unit})))))
+  [query                                         :- ::lib.schema/query
+   _stage-number                                 :- :int
+   {:keys [column dimensions row], :as _context} :- ::lib.schema.drill-thru/context]
+  ;; For multi-stage queries, we want the stage-number of the underlying stage with breakouts or aggregations.
+  ;; In such cases, the FE will not pass dimensions, so use the row data instead, if available.
+  (let [stage-number (lib.underlying/top-level-stage-number query)
+        dimensions   (or (not-empty dimensions)
+                         (lib.drill-thru.common/dimensions-from-breakout-columns query column row))]
+    (when (and (lib.drill-thru.common/mbql-stage? query stage-number)
+               dimensions)
+      (when-let [{:keys [value column-ref], :as dimension}
+                 (matching-breakout-dimension query stage-number dimensions)]
+        (when value
+          (when-let [next-unit (next-breakout-unit query stage-number column-ref)]
+            {:lib/type     :metabase.lib.drill-thru/drill-thru
+             :display-name (describe-next-unit next-unit)
+             :type         :drill-thru/zoom-in.timeseries
+             :dimension    dimension
+             :next-unit    next-unit}))))))
 
 (mu/defmethod lib.drill-thru.common/drill-thru-method :drill-thru/zoom-in.timeseries
   [query                         :- ::lib.schema/query
-   stage-number                  :- :int
+   _stage-number                 :- :int
    {:keys [dimension next-unit]} :- ::lib.schema.drill-thru/drill-thru.zoom-in.timeseries]
   (let [{:keys [column value]} dimension
         old-breakout           (:column-ref dimension)
-        new-breakout           (lib.temporal-bucket/with-temporal-bucket old-breakout next-unit)]
+        new-breakout           (lib.temporal-bucket/with-temporal-bucket old-breakout next-unit)
+        stage-number           (lib.underlying/top-level-stage-number query)]
     (-> query
         (lib.filter/filter stage-number (lib.filter/= column value))
         (lib.remove-replace/replace-clause stage-number old-breakout new-breakout))))
diff --git a/src/metabase/lib/field.cljc b/src/metabase/lib/field.cljc
index 5760dbf628b683add65790278305aefd387fed39..b04517ab899ccaae68093529a0f99a30fb5d25c2 100644
--- a/src/metabase/lib/field.cljc
+++ b/src/metabase/lib/field.cljc
@@ -100,8 +100,8 @@
                   ;; the [[lib.metadata.calculation/*propagate-inherited-temoral-unit*]] is thruthy, ie. bound. Intent
                   ;; is to pass it from ref to column only during [[returned-columns]] call. Otherwise eg.
                   ;; [[orderable-columns]] would contain that too. That could be problematic, because original ref that
-                  ;; contained `:temporal-unit` contains no `:inherent-temporal-unit`. If the column like this was used
-                  ;; to generate ref for eg. order by it would contain the `:inherent-temporal-unit`, while
+                  ;; contained `:temporal-unit` contains no `:inherited-temporal-unit`. If the column like this was used
+                  ;; to generate ref for eg. order by it would contain the `:inherited-temporal-unit`, while
                   ;; the original column (eg. in breakout) would not.
                   (let [inherited-temporal-unit-keys (cond-> (list :inherited-temporal-unit)
                                                        lib.metadata.calculation/*propagate-inherited-temoral-unit*
diff --git a/src/metabase/lib/underlying.cljc b/src/metabase/lib/underlying.cljc
index 46ee580ff4e0826a5a7ad1b10f5fbe867db3ccb8..9954475e314d46ef0623ada4afcd09c1e7302600 100644
--- a/src/metabase/lib/underlying.cljc
+++ b/src/metabase/lib/underlying.cljc
@@ -15,31 +15,51 @@
    [metabase.lib.util :as lib.util]
    [metabase.util.malli :as mu]))
 
-(mu/defn- pop-until-aggregation-or-breakout :- [:maybe ::lib.schema/query]
-  "Strips off any trailing stages that do not contain aggregations.
+(mu/defn- pop-until-aggregation-or-breakout :- [:tuple [:maybe ::lib.schema/query] [:int {:max -1}]]
+  "Strips off any trailing stages that do not contain aggregations or breakouts.
 
-  If there are no such stages, returns nil."
+  Returns a tuple of [query, stage-number] where `query` is the first stage with aggregations or breakouts and
+  `stage-number` is the (negative) index of that stage relative to the original query.
+
+  If there are no such stages, returns [nil, -1]."
   [query :- ::lib.schema/query]
-  (if (and (empty? (lib.aggregation/aggregations query -1))
-           (empty? (lib.breakout/breakouts query -1)))
-    ;; No aggregations or breakouts in the last stage, so pop it off and recur.
-    (let [popped (update query :stages pop)]
-      (when (seq (:stages popped))
-        (recur popped)))
-    query))
+  (loop [query query
+         i -1]
+    (if (and (empty? (lib.aggregation/aggregations query -1))
+             (empty? (lib.breakout/breakouts query -1)))
+      ;; No aggregations or breakouts in the last stage, so pop it off and recur.
+      (let [popped (update query :stages pop)]
+        (if (seq (:stages popped))
+          (recur popped (dec i))
+          [nil, -1]))
+      [query, i])))
+
+(mu/defn- query-database-supports? :- :boolean
+  [query   :- ::lib.schema/query
+   feature :- :keyword]
+  (contains? (-> query lib.metadata/database :features) feature))
 
 (mu/defn top-level-query :- ::lib.schema/query
   "Returns the \"top-level\" query for the given query.
 
-  That means dropping any trailing filters, fields, etc. to get back to the last stage that has an aggregation. If there
-  are no stages with aggregations, the original query is returned.
+  That means dropping any trailing filters, fields, etc. to get back to the last stage that has an aggregation or
+  breakout. If there are no such stages, the original query is returned.
 
-  If the database does not support nested queries, this also returns the original."
+  If the database does not support nested queries, this also returns the original query."
   [query :- ::lib.schema/query]
-  (or (when ((-> query lib.metadata/database :features) :nested-queries)
-        (pop-until-aggregation-or-breakout query))
+  (or (when (query-database-supports? query :nested-queries)
+        (first (pop-until-aggregation-or-breakout query)))
       query))
 
+(mu/defn top-level-stage-number :- :int
+  "Returns the stage-number of the [[top-level-query]] for the given query.
+
+  If there are no such stages, or if the database does not supported nested queries, returns -1."
+  [query :- ::lib.schema/query]
+  (or (when (query-database-supports? query :nested-queries)
+        (second (pop-until-aggregation-or-breakout query)))
+      -1))
+
 (mu/defn top-level-column :- ::lib.schema.metadata/column
   "Given a column, returns the \"top-level\" equivalent.
 
@@ -67,4 +87,4 @@
 (mu/defn has-aggregation-or-breakout?
   "Whether the `query` has an aggregation or breakout clause in some query stage."
   [query :- ::lib.schema/query]
-  (some? (pop-until-aggregation-or-breakout query)))
+  (some? (first (pop-until-aggregation-or-breakout query))))
diff --git a/test/metabase/lib/drill_thru/zoom_in_timeseries_test.cljc b/test/metabase/lib/drill_thru/zoom_in_timeseries_test.cljc
index 131053e7b0670bed0c62c12a487864fd1d424594..49d3a60e9410d173e95ad5db16b15da0cf8527cb 100644
--- a/test/metabase/lib/drill_thru/zoom_in_timeseries_test.cljc
+++ b/test/metabase/lib/drill_thru/zoom_in_timeseries_test.cljc
@@ -189,33 +189,77 @@
           bucketing
           {"CREATED_AT" "2022-12-01"}))))))
 
+(deftest ^:parallel returns-zoom-in-timeseries-for-multi-stage-queries
+  (lib.drill-thru.tu/test-returns-drill
+   {:drill-type   :drill-thru/zoom-in.timeseries
+    :click-type   :cell
+    :query-type   :aggregated
+    :column-name  "count"
+    :custom-query (let [base-query (-> (lib/query meta/metadata-provider (meta/table-metadata :orders))
+                                       (lib/aggregate (lib/count))
+                                       (lib/breakout (meta/field-metadata :orders :product-id))
+                                       (lib/breakout (-> (meta/field-metadata :orders :created-at)
+                                                         (lib/with-temporal-bucket :month)))
+                                       lib/append-stage)
+                        count-col  (m/find-first #(= (:name %) "count")
+                                                 (lib/returned-columns base-query))
+                        _          (is (some? count-col))]
+                    (lib/filter base-query (lib/> count-col 0)))
+    :custom-row   {"PRODUCT_ID" 3
+                   "CREATED_AT" "2023-12-01"
+                   "count"      77}
+    :expected     {:type      :drill-thru/zoom-in.timeseries
+                   :next-unit :week
+                   ;; the "underlying" dimension is reconstructed from the row.
+                   :dimension {:column     {:name       "CREATED_AT"
+                                            :lib/source :source/breakouts}
+                               :column-ref [:field {} (meta/id :orders :created-at)]
+                               :value      "2023-12-01"}}}))
+
 (deftest ^:parallel returns-zoom-in-timeseries-e2e-test-2
   (testing "zoom-in.timeseries should be returned for a"
-    (let [query          (-> (lib/query meta/metadata-provider (meta/table-metadata :orders))
-                             (lib/aggregate (lib/count))
-                             (lib/breakout (-> (meta/field-metadata :orders :created-at)
-                                               (lib/with-temporal-bucket :year))))
-          created-at-col (m/find-first #(= (:name %) "CREATED_AT")
-                                       (lib/returned-columns query))
-          _              (is (some? created-at-col))]
-      (doseq [[message context] {"pivot cell (no column, value = NULL) (#36173)"
-                                 {:value      :null
-                                  :column     nil
-                                  :column-ref nil
-                                  :dimensions [{:column     created-at-col
-                                                :column-ref (lib/ref created-at-col)
-                                                :value      "2022-12-01T00:00:00+02:00"}]}
+    (let [base-query        (-> (lib/query meta/metadata-provider (meta/table-metadata :orders))
+                                (lib/aggregate (lib/count))
+                                (lib/breakout (-> (meta/field-metadata :orders :created-at)
+                                                  (lib/with-temporal-bucket :year))))
+          created-at-col    (m/find-first #(= (:name %) "CREATED_AT")
+                                          (lib/returned-columns base-query))
+          _                 (is (some? created-at-col))
+          multi-stage-query (lib/append-stage base-query)
+          count-col         (m/find-first #(= (:name %) "count")
+                                          (lib/returned-columns multi-stage-query))
+          _                 (is (some? count-col))
+          multi-stage-query (lib/filter multi-stage-query (lib/> count-col 0))]
+      (doseq [[query-type query] {"single-stage" base-query
+                                  "multi-stage" multi-stage-query}
+              [message context]  {"pivot cell (no column, value = NULL) (#36173)"
+                                  {:value      :null
+                                   :column     nil
+                                   :column-ref nil
+                                   :dimensions [{:column     created-at-col
+                                                 :column-ref (lib/ref created-at-col)
+                                                 :value      "2022-12-01T00:00:00+02:00"}]}
 
-                                 "legend item (no column, no value) (#36173)"
-                                 {:value      nil
-                                  :column     nil
-                                  :column-ref nil
-                                  :dimensions [{:column     created-at-col
-                                                :column-ref (lib/ref created-at-col)
-                                                :value      "2022-12-01T00:00:00+02:00"}]}}]
-        (testing message
+                                  "legend item (no column, no value) (#36173)"
+                                  {:value      nil
+                                   :column     nil
+                                   :column-ref nil
+                                   :dimensions [{:column     created-at-col
+                                                 :column-ref (lib/ref created-at-col)
+                                                 :value      "2022-12-01T00:00:00+02:00"}]}}]
+        (testing (str query-type " query: " message)
           (let [[drill :as drills] (filter #(= (:type %) :drill-thru/zoom-in.timeseries)
-                                           (lib/available-drill-thrus query -1 context))]
+                                           (lib/available-drill-thrus query -1 context))
+                ;; both queries have the base-query stage where the drill filter should be added
+                expected-stages (cond-> [{:aggregation [[:count {}]]
+                                          :breakout    [[:field {:temporal-unit :quarter} (meta/id :orders :created-at)]],
+                                          :filters     [[:=
+                                                         {}
+                                                         [:field {:temporal-unit :year} (meta/id :orders :created-at)]
+                                                         "2022-12-01T00:00:00+02:00"]]}]
+                                  ;; the multi-stage-query has an additional filter stage
+                                  (= query multi-stage-query) (conj {:filters
+                                                                     [[:> {} [:field {} "count"] 0]]}))]
             (is (= 1
                    (count drills)))
             (is (=? {:lib/type     :metabase.lib.drill-thru/drill-thru
@@ -225,43 +269,49 @@
                                     :value  "2022-12-01T00:00:00+02:00"}
                      :next-unit    :quarter}
                     drill))
-            (is (=? {:stages [{:aggregation [[:count {}]]
-                               :breakout    [[:field {:temporal-unit :quarter} (meta/id :orders :created-at)]],
-                               :filters     [[:=
-                                              {}
-                                              [:field {:temporal-unit :year} (meta/id :orders :created-at)]
-                                              "2022-12-01T00:00:00+02:00"]]}]}
+            (is (=? {:stages expected-stages}
                     (lib/drill-thru query -1 nil drill)))))))))
 
 (deftest ^:parallel zoom-in-timeseries-unit-tower-test
   (doseq [[unit1 unit2] datetime-unit-pairs]
-    (testing (str "zoom-in.timeseries for a DateTime column should zoom from " unit1 " to " unit2)
-      (let [query (-> (lib/query meta/metadata-provider (meta/table-metadata :orders))
-                      (lib/aggregate (lib/count))
-                      (lib/breakout (-> (meta/field-metadata :orders :created-at)
-                                        (lib/with-temporal-bucket unit1))))]
-        (lib.drill-thru.tu/test-drill-application
-         {:click-type     :cell
-          :query-type     :aggregated
-          :custom-query   query
-          :custom-row     {"count"      100
-                           "CREATED_AT" "2022-12-09T11:22:33+02:00"}
-          :column-name    "count"
-          :drill-type     :drill-thru/zoom-in.timeseries
-          :expected       {:type         :drill-thru/zoom-in.timeseries
-                           :display-name (str "See this " (name unit1) " by " (name unit2))
-                           :dimension    {:column     {:name "CREATED_AT"}
-                                          :column-ref [:field {:temporal-unit unit1} (meta/id :orders :created-at)]
-                                          :value      "2022-12-09T11:22:33+02:00"}
-                           :next-unit    unit2}
-          :expected-query {:stages [{:source-table (meta/id :orders)
-                                     :aggregation  [[:count {}]]
-                                     :breakout     [[:field
-                                                     {:temporal-unit unit2}
-                                                     (meta/id :orders :created-at)]]
-                                     :filters      [[:= {}
-                                                     [:field {:temporal-unit unit1} (meta/id :orders :created-at)]
-                                                     "2022-12-09T11:22:33+02:00"]]}]}})))))
+    (let [base-query        (-> (lib/query meta/metadata-provider (meta/table-metadata :orders))
+                                (lib/aggregate (lib/count))
+                                (lib/breakout (-> (meta/field-metadata :orders :created-at)
+                                                  (lib/with-temporal-bucket unit1))))
+          multi-stage-query (lib/append-stage base-query)
+          count-col         (m/find-first #(= (:name %) "count")
+                                          (lib/returned-columns multi-stage-query))
+          _                 (is (some? count-col))
+          multi-stage-query (lib/filter multi-stage-query (lib/> count-col 0))]
+      (doseq [[query-type query] {"single-stage" base-query
+                                  "multi-stage"  multi-stage-query}]
+        (testing (str "zoom-in.timeseries for a DateTime column in a " query-type " query should zoom from " unit1 " to " unit2)
+          (let [expected-stages (cond-> [{:source-table (meta/id :orders)
+                                          :aggregation  [[:count {}]]
+                                          :breakout     [[:field
+                                                          {:temporal-unit unit2}
+                                                          (meta/id :orders :created-at)]]
+                                          :filters      [[:= {}
+                                                          [:field {:temporal-unit unit1} (meta/id :orders :created-at)]
+                                                          "2022-12-09T11:22:33+02:00"]]}]
+                                  ;; the multi-stage-query has an additional filter stage
+                                  (= query multi-stage-query) (conj {:filters
+                                                                     [[:> {} [:field {} "count"] 0]]}))]
+            (lib.drill-thru.tu/test-drill-application
+             {:click-type     :cell
+              :query-type     :aggregated
+              :custom-query   query
+              :custom-row     {"count"      100
+                               "CREATED_AT" "2022-12-09T11:22:33+02:00"}
+              :column-name    "count"
+              :drill-type     :drill-thru/zoom-in.timeseries
+              :expected       {:type         :drill-thru/zoom-in.timeseries
+                               :display-name (str "See this " (name unit1) " by " (name unit2))
+                               :dimension    {:column     {:name "CREATED_AT"}
+                                              :column-ref [:field {:temporal-unit unit1} (meta/id :orders :created-at)]
+                                              :value      "2022-12-09T11:22:33+02:00"}
+                               :next-unit    unit2}
+              :expected-query {:stages expected-stages}})))))))
 
 (deftest ^:parallel zoom-in-timeseries-unit-tower-test-2
   (doseq [[unit1 unit2] date-unit-pairs]
diff --git a/test/metabase/lib/drill_thru_test.cljc b/test/metabase/lib/drill_thru_test.cljc
index 695e522b1ce5a77024047f3233aac78b18090330..3f377eab2047cfefb8a94dcda09bbd005b636d1e 100644
--- a/test/metabase/lib/drill_thru_test.cljc
+++ b/test/metabase/lib/drill_thru_test.cljc
@@ -554,11 +554,10 @@
                                              :month)))
             columns      (lib/returned-columns query)
             sum          (by-name columns "sum")
-            breakout     (by-name columns "CREATED_AT")
             sum-dim      {:column     sum
                           :column-ref (lib/ref sum)
                           :value      42295.12}
-            breakout-dim {:column     breakout
+            breakout-dim {:column     (first (lib/breakouts-metadata query))
                           :column-ref (first (lib/breakouts query))
                           :value      "2024-11-01T00:00:00Z"}
             context      (merge sum-dim