diff --git a/Framework/API/src/WorkspaceOpOverloads.cpp b/Framework/API/src/WorkspaceOpOverloads.cpp
index 653d2f7fe806e2848837efec87d9d81d3085a081..362c9a63288cbb1d4e7ed0530e55d81b004cdd83 100644
--- a/Framework/API/src/WorkspaceOpOverloads.cpp
+++ b/Framework/API/src/WorkspaceOpOverloads.cpp
@@ -405,8 +405,9 @@ MatrixWorkspace_sptr operator/=(const MatrixWorkspace_sptr lhs,
  *  @return True if the bins match
  */
 bool WorkspaceHelpers::commonBoundaries(const MatrixWorkspace &WS) {
-  if (!WS.blocksize() || WS.getNumberHistograms() < 2)
+  if (WS.getNumberHistograms() < 2 || WS.size() == 0)
     return true;
+
   // Quickest check is to see if they are actually all the same vector
   if (sharedXData(WS))
     return true;
diff --git a/Framework/Algorithms/inc/MantidAlgorithms/ExtractSpectra.h b/Framework/Algorithms/inc/MantidAlgorithms/ExtractSpectra.h
index 60f9e65fc4f674b2fba6147f57b71c5542ed5d23..eda7d0939fa56808b607aca9dd59aba0359a3232 100644
--- a/Framework/Algorithms/inc/MantidAlgorithms/ExtractSpectra.h
+++ b/Framework/Algorithms/inc/MantidAlgorithms/ExtractSpectra.h
@@ -47,8 +47,8 @@ private:
   void execEvent();
 
   void checkProperties();
-  std::size_t getXMin(const int wsIndex = 0);
-  std::size_t getXMax(const int wsIndex = 0);
+  std::size_t getXMin(const size_t wsIndex = 0);
+  std::size_t getXMax(const size_t wsIndex = 0);
   void cropRagged(API::MatrixWorkspace_sptr outputWorkspace, int inIndex,
                   int outIndex);
 
@@ -72,4 +72,4 @@ private:
 } // namespace Algorithms
 } // namespace Mantid
 
-#endif /* MANTID_ALGORITHMS_EXTRACTSPECTRA_H_ */
\ No newline at end of file
+#endif /* MANTID_ALGORITHMS_EXTRACTSPECTRA_H_ */
diff --git a/Framework/Algorithms/src/ExtractSpectra.cpp b/Framework/Algorithms/src/ExtractSpectra.cpp
index 38495d629eb7e3f6c719d142aaea6f792e85e5df..216e46bc3a6aee87acee4e45b7d6fe29d9b7df27 100644
--- a/Framework/Algorithms/src/ExtractSpectra.cpp
+++ b/Framework/Algorithms/src/ExtractSpectra.cpp
@@ -365,26 +365,6 @@ void ExtractSpectra::execEvent() {
  * input workspace
  */
 void ExtractSpectra::checkProperties() {
-  m_minX = this->getXMin();
-  m_maxX = this->getXMax();
-  const size_t xSize = m_inputWorkspace->x(0).size();
-  if (m_minX > 0 || m_maxX < xSize) {
-    if (m_minX > m_maxX) {
-      g_log.error("XMin must be less than XMax");
-      throw std::out_of_range("XMin must be less than XMax");
-    }
-    if (m_minX == m_maxX && m_commonBoundaries && eventW == nullptr) {
-      g_log.error("The X range given lies entirely within a single bin");
-      throw std::out_of_range(
-          "The X range given lies entirely within a single bin");
-    }
-    m_croppingInX = true;
-  }
-  if (!m_commonBoundaries)
-    m_minX = 0;
-  if (!m_commonBoundaries)
-    m_maxX = static_cast<int>(m_inputWorkspace->x(0).size());
-
   // The hierarchy of inputs is (one is being selected):
   // 1. DetectorList
   // 2. WorkspaceIndexList
@@ -397,11 +377,12 @@ void ExtractSpectra::checkProperties() {
     m_workspaceIndexList = getProperty("WorkspaceIndexList");
 
     if (m_workspaceIndexList.empty()) {
-      int minSpec = getProperty("StartWorkspaceIndex");
-      const int numberOfSpectra =
-          static_cast<int>(m_inputWorkspace->getNumberHistograms());
-      int maxSpec = getProperty("EndWorkspaceIndex");
-      if (isEmpty(maxSpec))
+      int minSpec_i = getProperty("StartWorkspaceIndex");
+      size_t minSpec = static_cast<size_t>(minSpec_i);
+      const size_t numberOfSpectra = m_inputWorkspace->getNumberHistograms();
+      int maxSpec_i = getProperty("EndWorkspaceIndex");
+      size_t maxSpec = static_cast<size_t>(maxSpec_i);
+      if (isEmpty(maxSpec_i))
         maxSpec = numberOfSpectra - 1;
 
       // Check 'StartSpectrum' is in range 0-numberOfSpectra
@@ -427,6 +408,32 @@ void ExtractSpectra::checkProperties() {
       }
     }
   }
+
+  // get the x-range from the used spectra
+  size_t spectrumIndex = 0; // default is just look at the initial spectrum
+  if (!m_workspaceIndexList.empty())
+    spectrumIndex =
+        m_workspaceIndexList.front(); // or the first one being extracted
+
+  m_minX = this->getXMin(spectrumIndex);
+  m_maxX = this->getXMax(spectrumIndex);
+  const size_t xSize = m_inputWorkspace->x(spectrumIndex).size();
+  if (m_minX > 0 || m_maxX < xSize) {
+    if (m_minX > m_maxX) {
+      g_log.error("XMin must be less than XMax");
+      throw std::out_of_range("XMin must be less than XMax");
+    }
+    if (m_minX == m_maxX && m_commonBoundaries && eventW == nullptr) {
+      g_log.error("The X range given lies entirely within a single bin");
+      throw std::out_of_range(
+          "The X range given lies entirely within a single bin");
+    }
+    m_croppingInX = true;
+  }
+  if (!m_commonBoundaries)
+    m_minX = 0;
+  if (!m_commonBoundaries)
+    m_maxX = static_cast<int>(m_inputWorkspace->x(spectrumIndex).size());
 }
 
 /** Find the X index corresponding to (or just within) the value given in the
@@ -435,7 +442,7 @@ void ExtractSpectra::checkProperties() {
  *  @param  wsIndex The workspace index to check (default 0).
  *  @return The X index corresponding to the XMin value.
  */
-size_t ExtractSpectra::getXMin(const int wsIndex) {
+size_t ExtractSpectra::getXMin(const size_t wsIndex) {
   double minX_val = getProperty("XMin");
   size_t xIndex = 0;
   if (!isEmpty(minX_val)) { // A value has been passed to the algorithm, check
@@ -462,8 +469,8 @@ size_t ExtractSpectra::getXMin(const int wsIndex) {
  *  @param  wsIndex The workspace index to check (default 0).
  *  @return The X index corresponding to the XMax value.
  */
-size_t ExtractSpectra::getXMax(const int wsIndex) {
-  auto &X = m_inputWorkspace->x(wsIndex);
+size_t ExtractSpectra::getXMax(const size_t wsIndex) {
+  const auto &X = m_inputWorkspace->x(wsIndex);
   size_t xIndex = X.size();
   // get the value that the user entered if they entered one at all
   double maxX_val = getProperty("XMax");
diff --git a/docs/source/release/v3.12.0/framework.rst b/docs/source/release/v3.12.0/framework.rst
index e9096578e0629614f938efc44c79fe1148ae399e..1c2907088ee7409c1b57e0d015f99e116891d74f 100644
--- a/docs/source/release/v3.12.0/framework.rst
+++ b/docs/source/release/v3.12.0/framework.rst
@@ -25,6 +25,7 @@ Algorithms
 :ref:`NormaliseToMonitor <algm-NormaliseToMonitor>` now supports workspaces with detector scans and workspaces with single-count point data.
 - :ref:`CreateWorkspace <algm-CreateWorkspace>` will no longer create a default (and potentially wrong) mapping from spectra to detectors, unless a parent workspace is given. This change ensures that accidental bad mappings that could lead to corrupted data are not created silently anymore. This change does *not* affect the use of this algorithm if: (1) a parent workspace is given, or (2) no instrument is loaded into to workspace at a later point, or (3) an instrument is loaded at a later point but ``LoadInstrument`` is used with ``RewriteSpectraMapping=True``. See also the algorithm documentation for details.
 - :ref:`Fit <algm-Fit>` will now respect excluded ranges when ``CostFunction = 'Unweighted least squares'``.
+- :ref:`NormaliseToMonitor <algm-NormaliseToMonitor>` now supports non-constant number of bins.
 
 Core Functionality
 ------------------