diff --git a/Framework/DataHandling/src/ParallelEventLoader.cpp b/Framework/DataHandling/src/ParallelEventLoader.cpp
index 0b178aaa5539fca1b4c4d415bf088370a3b0ca3b..88dfd283cd528e95fa1380aba14518d9aef506db 100644
--- a/Framework/DataHandling/src/ParallelEventLoader.cpp
+++ b/Framework/DataHandling/src/ParallelEventLoader.cpp
@@ -1,61 +1,44 @@
 #include "MantidDataHandling/ParallelEventLoader.h"
 #include "MantidDataObjects/EventWorkspace.h"
-#include "MantidGeometry/Instrument.h"
-#include "MantidGeometry/Instrument/ComponentInfo.h"
 #include "MantidGeometry/Instrument/DetectorInfo.h"
 #include "MantidParallel/IO/EventLoader.h"
+#include "MantidTypes/SpectrumDefinition.h"
 #include "MantidTypes/Event/TofEvent.h"
 
 namespace Mantid {
 namespace DataHandling {
 
 std::vector<int32_t> bankOffsets(const API::ExperimentInfo &ws,
+                                 const std::string &filename,
+                                 const std::string &groupName,
                                  const std::vector<std::string> &bankNames) {
-  const auto instrument = ws.getInstrument();
-  const auto &compInfo = ws.componentInfo();
+  // Build detector ID to spectrum index map. Used only in LoadEventNexus so we
+  // know there is a 1:1 mapping, omitting monitors.
   const auto &detInfo = ws.detectorInfo();
   const auto &detIDs = detInfo.detectorIDs();
+  std::unordered_map<detid_t, int32_t> map;
+  int32_t spectrumIndex{0}; // *global* index
+  for (size_t i = 0; i < detInfo.size(); ++i)
+    if (!detInfo.isMonitor(i))
+      map[detIDs[i]] = spectrumIndex++;
 
-  // Monitors are not loaded by LoadEventNexus, so we have to exclude them when
-  // computing an offset based on detector IDs. Currently this is computed in a
-  // naive way and works only if all monitors have IDs smaller than any
-  // detector.
-  int32_t monitorOffset{0};
-  bool sawDetector{false};
-  for (size_t i = 0; i < detInfo.size(); ++i) {
-    if (detInfo.isMonitor(i)) {
-      if (sawDetector)
-        throw std::runtime_error("Monitors are not corresponding to the first "
-                                 "detector IDs in the instrument. This is "
-                                 "currently not supported by "
-                                 "ParallelEventLoader");
-      ++monitorOffset;
-    } else {
-      sawDetector = true;
-    }
-  }
-
+  // Load any event ID and determine offset from it. This is always a detector
+  // ID since the parallel loader is disabled otherwise. It is assumed that
+  // detector IDs within a bank are contiguous.
   std::vector<int32_t> bankOffsets;
-  for (const auto &bankName : bankNames) {
-    // Removing "_events" from bankName
-    auto bank =
-        instrument->getComponentByName(bankName.substr(0, bankName.size() - 7));
-    if (bank) {
-      const auto &detectors =
-          compInfo.detectorsInSubtree(compInfo.indexOf(bank->getComponentID()));
-      const size_t detIndex = detectors.front();
-      bankOffsets.push_back(detIDs[detIndex] - static_cast<int32_t>(detIndex) +
-                            monitorOffset);
-      if ((detIDs[detectors.back()] - detIDs[detectors.front()]) !=
-          static_cast<int32_t>(detectors.size()) - 1)
-        throw std::runtime_error("Detector ID range in bank is not contiguous. "
-                                 "Cannot use ParallelEventLoader.");
-    } else {
-      throw std::runtime_error(
-          "ParallelEventLoader: Bank " + bankName +
-          " not found. Cannot determine detector ID offset.");
-    }
+  for (const auto &eventId : Parallel::IO::EventLoader::anyEventIdFromBanks(
+           filename, groupName, bankNames)) {
+    // The offset is the difference between the event ID and the spectrum index
+    // and can then be used to translate from the former to the latter by simple
+    // subtraction.
+    // If no eventId could be read for a bank it implies that there are no
+    // events, so any offset will do since it is unused. Set to 0.
+    if (eventId)
+      bankOffsets.emplace_back(*eventId - map.at(*eventId));
+    else
+      bankOffsets.emplace_back(0);
   }
+
   return bankOffsets;
 }
 
@@ -68,9 +51,9 @@ void ParallelEventLoader::load(DataObjects::EventWorkspace &ws,
   for (size_t i = 0; i < size; ++i)
     DataObjects::getEventsFrom(ws.getSpectrum(i), eventLists[i]);
 
-  Parallel::IO::EventLoader::load(filename, groupName, bankNames,
-                                  bankOffsets(ws, bankNames),
-                                  std::move(eventLists));
+  Parallel::IO::EventLoader::load(
+      filename, groupName, bankNames,
+      bankOffsets(ws, filename, groupName, bankNames), std::move(eventLists));
 }
 
 } // namespace DataHandling
diff --git a/Framework/Parallel/inc/MantidParallel/IO/EventLoader.h b/Framework/Parallel/inc/MantidParallel/IO/EventLoader.h
index b7089fcef38a52fc9f1999ca100deebbbdfeec27..aea1261e50015f43416bf8f00a4c919f8da9e5b2 100644
--- a/Framework/Parallel/inc/MantidParallel/IO/EventLoader.h
+++ b/Framework/Parallel/inc/MantidParallel/IO/EventLoader.h
@@ -5,6 +5,8 @@
 #include <string>
 #include <vector>
 
+#include <boost/optional.hpp>
+
 #include "MantidParallel/DllConfig.h"
 
 namespace Mantid {
@@ -44,6 +46,9 @@ namespace IO {
   Code Documentation is available at: <http://doxygen.mantidproject.org>
 */
 namespace EventLoader {
+MANTID_PARALLEL_DLL std::vector<boost::optional<int32_t>>
+anyEventIdFromBanks(const std::string &filename, const std::string &groupName,
+                    const std::vector<std::string> &bankNames);
 MANTID_PARALLEL_DLL void
 load(const std::string &filename, const std::string &groupName,
      const std::vector<std::string> &bankNames,
diff --git a/Framework/Parallel/src/IO/EventLoader.cpp b/Framework/Parallel/src/IO/EventLoader.cpp
index cad71a49b21c12fad0cf5dfd0eb03d69aafbb48e..19e6d3c851d3af08b60dfe2dca7763853773c55a 100644
--- a/Framework/Parallel/src/IO/EventLoader.cpp
+++ b/Framework/Parallel/src/IO/EventLoader.cpp
@@ -1,5 +1,6 @@
 #include "MantidParallel/IO/EventLoader.h"
 #include "MantidParallel/IO/EventLoaderHelpers.h"
+#include "MantidParallel/IO/NXEventDataLoader.h"
 
 #include <H5Cpp.h>
 
@@ -8,6 +9,24 @@ namespace Parallel {
 namespace IO {
 namespace EventLoader {
 
+std::vector<boost::optional<int32_t>>
+anyEventIdFromBanks(const std::string &filename, const std::string &groupName,
+                    const std::vector<std::string> &bankNames) {
+  std::vector<boost::optional<int32_t>> eventIds(bankNames.size());
+  H5::H5File file(filename, H5F_ACC_RDONLY);
+  H5::Group group = file.openGroup(groupName);
+  for (size_t i = 0; i < bankNames.size(); ++i) {
+    try {
+      int32_t eventId;
+      detail::read<int32_t>(&eventId, group, bankNames[i] + "/event_id", 0, 1);
+      eventIds[i] = eventId;
+    } catch (const std::out_of_range &) {
+      // No event in file, keep eventIds uninitialized for this bank.
+    }
+  }
+  return eventIds;
+}
+
 void load(const std::string &filename, const std::string &groupName,
           const std::vector<std::string> &bankNames,
           const std::vector<int32_t> &bankOffsets,