diff --git a/src/mongo/db/query/ce/max_diff.cpp b/src/mongo/db/query/ce/max_diff.cpp
index 0fcff05b542..c48bbeafd4b 100644
--- a/src/mongo/db/query/ce/max_diff.cpp
+++ b/src/mongo/db/query/ce/max_diff.cpp
@@ -129,49 +129,67 @@ DataDistribution getDataDistribution(const std::vector<SBEValue>& sortedInput) {
         }
     }
 
-    // Calculate the area for all values in the data distribution.
-    // The current minimum and maximum areas of the values of a type class.
-    double maxArea = 0.0;
+    double maxArea = -1.0;      // Illegal value
+    double maxAreaDiff = -1.0;  // Illegal value
 
-    for (size_t i = 0; i + 1 < result._freq.size(); ++i) {
+    // Calculate the area for all values in the data distribution.
+    for (size_t i = 0; i < result._freq.size() - 1; ++i) {
         const auto v1 = result._bounds[i];
         const auto v2 = result._bounds[i + 1];
         const bool newTypeClass = !sameTypeClass(v1.getTag(), v2.getTag());
 
-        if (newTypeClass) {
-            const auto res = result.typeClassBounds.emplace(i, maxArea);
-            uassert(0, "There can't be duplicate type class bounds.", res.second);
-            maxArea = 0.0;
-        } else if (i == 0) {
-            const double spread =
-                valueSpread(v1.getTag(), v1.getValue(), v2.getTag(), v2.getValue());
-            maxArea = result._freq[i]._freq * spread;
-        }
-
         if (i == 0 || newTypeClass) {
             // Make sure we insert bucket boundaries between different types, and also make sure
             // first value is picked for a boundary.
             result._freq[i]._area = std::numeric_limits<double>::infinity();
+            result._freq[i]._areaDiff = std::numeric_limits<double>::infinity();
+            if (newTypeClass) {
+                ++i;  // Ensure that the first boundary of each type is picked as well
+                result._freq[i]._area = std::numeric_limits<double>::infinity();
+                result._freq[i]._areaDiff = std::numeric_limits<double>::infinity();
+                continue;
+            }
+            maxArea = 0.0;
+            maxAreaDiff = 0.0;
         } else {
             const double spread =
                 valueSpread(v1.getTag(), v1.getValue(), v2.getTag(), v2.getValue());
             result._freq[i]._area = result._freq[i]._freq * spread;
-            maxArea = std::max(maxArea, result._freq[i]._area);
+            double curArea = result._freq[i]._area;
+            double prevArea = result._freq[i - 1]._area;
+            result._freq[i]._areaDiff =
+                (i == 1 || prevArea == std::numeric_limits<double>::infinity())
+                ? result._freq[i]._area
+                : std::abs(curArea - prevArea);
+            double curAreaDiff = result._freq[i]._areaDiff;
+
+            uassert(0,
+                    "curArea < inf",
+                    curArea > 0.0 && curArea < std::numeric_limits<double>::infinity());
+            uassert(0,
+                    "curAreaDiff < inf",
+                    curAreaDiff >= 0.0 && curAreaDiff < std::numeric_limits<double>::infinity());
+            maxArea = std::max(maxArea, curArea);
+            maxAreaDiff = std::max(maxAreaDiff, curAreaDiff);
         }
+        uassert(0, "Non-exitent frequency position.", i == result._freq[i]._idx);
     }
 
     // Make sure last value is picked as a histogram bucket boundary.
     result._freq.back()._area = std::numeric_limits<double>::infinity();
-    const auto res = result.typeClassBounds.emplace(result._freq.size(), maxArea);
+    result._freq.back()._areaDiff = std::numeric_limits<double>::infinity();
+    const auto res =
+        result.typeClassBounds.emplace(result._freq.size(), std::make_pair(maxArea, maxAreaDiff));
     uassert(0, "There can't be duplicate type class bounds.", res.second);
 
     // Compute normalized areas.
     size_t beginIdx = 0;
-    for (const auto [endIdx, area] : result.typeClassBounds) {
+    for (const auto [endIdx, areaInfo] : result.typeClassBounds) {
         for (size_t i = beginIdx; i < endIdx; ++i) {
-            result._freq[i]._normArea = result._freq[i]._area / area;
+            result._freq[i]._normArea = result._freq[i]._area / areaInfo.first;
+            result._freq[i]._normAreaDiff = result._freq[i]._areaDiff / areaInfo.second;
         }
-        beginIdx = endIdx;
+        beginIdx = endIdx;  // Normalize values of the next type.
     }
 
     // std::cout << "Distribution sorted by value:\n"
@@ -186,8 +204,10 @@ static std::vector<ValFreq> generateTopKBuckets(const DataDistribution& dataDist
     struct AreaComparator {
         bool operator()(const ValFreq& a, const ValFreq& b) const {
             // TODO: the alternatives below allow to experiment with original vs normalized areas
-            // return a._area > b._area;
-            return a._normArea > b._normArea;
+            // return a._area         > b._area;
+            // return a._areaDiff     > b._areaDiff;
+            // return a._normArea     > b._normArea;
+            // return a._normAreaDiff > b._normAreaDiff;
         }
     };
     std::priority_queue<ValFreq, std::vector<ValFreq>, AreaComparator> pq;
diff --git a/src/mongo/db/query/ce/max_diff.h b/src/mongo/db/query/ce/max_diff.h
index 3b626af3ae7..a86d8e40f1f 100644
--- a/src/mongo/db/query/ce/max_diff.h
+++ b/src/mongo/db/query/ce/max_diff.h
@@ -39,26 +39,36 @@
 namespace mongo::ce {
 
 struct ValFreq {
-    ValFreq(size_t idx, size_t freq) : _idx(idx), _freq(freq), _area(-1.0), _normArea(-1) {}
+    ValFreq(size_t idx, size_t freq)
+        : _idx(idx),
+          _freq(freq),
+          _area(-1.0),
+          _areaDiff(-1.0),
+          _normArea(-1.0),
+          _normAreaDiff(-1.0) {}
 
     const std::string toString() const {
         std::ostringstream os;
         os << "idx: " << _idx << ", freq: " << _freq << ", area: " << _area
-           << ", normArea: " << _normArea;
+           << ", areaDiff:" << _areaDiff << ", normArea: " << _normArea
+           << ", normAreaDiff: " << _normAreaDiff;
         return os.str();
     }
 
-    size_t _idx;       // Original index according to value order.
-    size_t _freq;      // Frequency of the value.
-    double _area;      // Derived as: spread * frequency
-    double _normArea;  // Area normalized to the maximum in a type class.
+    size_t _idx;           // Original index according to value order.
+    size_t _freq;          // Frequency of the value.
+    double _area;          // Derived as: spread * frequency
+    double _areaDiff;      // Difference of thwo neighboring areas
+    double _normArea;      // Area normalized to the maximum in a type class.
+    double _normAreaDiff;  // Area difference normalized to the maximum difference in a type class.
 };
 
 struct DataDistribution {
     std::vector<SBEValue> _bounds;
     std::vector<ValFreq> _freq;
     // The min/max areas of each type class. The key is the index of the last element of the class.
-    std::map<size_t, double> typeClassBounds;
+    // The value is a pair of maximum area, and maximum area difference.
+    std::map<size_t, std::pair<double /* area */, double /*area diff*/>> typeClassBounds;
 };
 
 DataDistribution getDataDistribution(const std::vector<SBEValue>& sortedInput);
diff --git a/src/mongo/db/query/ce/maxdiff_histogram_test.cpp b/src/mongo/db/query/ce/maxdiff_histogram_test.cpp
index 70f0d8c6a7e..f9fe650b1f4 100644
--- a/src/mongo/db/query/ce/maxdiff_histogram_test.cpp
+++ b/src/mongo/db/query/ce/maxdiff_histogram_test.cpp
@@ -202,8 +202,8 @@ TEST_F(HistogramTest, MaxDiffTestInt) {
     ASSERT_GTE(hist.getBuckets().size(), nBuckets);
     const double expectedCard = estimateCard(hist, 10, EstimationType::kLess);
 
-    ASSERT_EQ(36, actualCard);
-    ASSERT_EQ(31.0, expectedCard);
+    ASSERT_EQ(36.0, actualCard);
+    ASSERT_EQ(32.0, expectedCard);
 }
 
 /*
@@ -288,7 +288,7 @@ TEST_F(HistogramTest, MaxDiffTestMixedTypes) {
     const double expectedCard = estimateCard(hist, 10, EstimationType::kLess);
 
     ASSERT_EQ(18, actualCard);
-    ASSERT_EQ(16.5, expectedCard);
+    ASSERT_EQ(24.5, expectedCard);
 }
 
 TEST_F(HistogramTest, MaxDiffIntArrays) {
@@ -332,8 +332,8 @@ TEST_F(HistogramTest, MaxDiffIntArrays) {
                                                                 tag,
                                                                 val);
 
-        ASSERT_EQ(5.5, expectedCard);
         ASSERT_EQ(6, actualCard);
+        ASSERT_EQ(6, expectedCard);
     }
 
     {
@@ -353,7 +353,7 @@ TEST_F(HistogramTest, MaxDiffIntArrays) {
                                                                 highTag,
                                                                 highVal);
 
-        ASSERT_APPROX_EQUAL(3.6, expectedCard, 0.1);
+        ASSERT_APPROX_EQUAL(3.35, expectedCard, 0.1);
         ASSERT_EQ(3, actualCard);
     }
 }
