diff --git a/Control/AthenaMonitoring/python/TriggerInterface.py b/Control/AthenaMonitoring/python/TriggerInterface.py
index 6f3eadf781358a53ed6a2d9c339c4faccbd250b8..aabdad10adfb979c6d7184d0daa125657644a97d 100644
--- a/Control/AthenaMonitoring/python/TriggerInterface.py
+++ b/Control/AthenaMonitoring/python/TriggerInterface.py
@@ -8,64 +8,11 @@
 @brief Simple new configuration framework functions for getting a TrigDecisionTool. Probably do not work except for reading ESD and AOD. Will be superseded by proper code from Trigger.
 '''
 
-def getTrigConfigSvc(flags):
-    ''' Setup a TrigConfigSvc with DS information. Works on AOD, not vetted for anything else! '''
-    from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator
-    from TrigConfigSvc.TrigConfigSvcConfig import DSConfigSvc, SetupTrigConfigSvc
-    from IOVDbSvc.IOVDbSvcConfig import addFolders
-    from EventInfoMgt.TagInfoMgrConfig import TagInfoMgrCfg
-
-    rv = ComponentAccumulator()
-    # is MC ? then set up XML reading and get out of here
-    if flags.Input.isMC:
-        from TrigConfigSvc.TrigConfigSvcConfig import (HLTConfigSvc, LVL1ConfigSvc, L1TopoConfigSvc, 
-                                                       findFileInXMLPATH, TrigConfigSvc)
-        hltcs = HLTConfigSvc("HLTConfigSvc")
-        hltcs.XMLMenuFile = findFileInXMLPATH(flags.Trigger.HLTMenuFile)
-        rv.addService(hltcs)
-        lvl1cs = LVL1ConfigSvc("LVL1ConfigSvc")
-        # Configures here via "newJO" but XMLs not generated for this menu name
-        lvl1XML = flags.Trigger.LVL1ConfigFile.replace('newJO_', '')
-        lvl1cs.XMLMenuFile = findFileInXMLPATH(lvl1XML)
-        rv.addService(lvl1cs)
-        l1topocs = L1TopoConfigSvc()
-        l1topocs.XMLMenuFile = findFileInXMLPATH(flags.Trigger.LVL1TopoConfigFile)
-        rv.addService(l1topocs)
-        ts = TrigConfigSvc("TrigConfigSvc")
-        # run3_dummy - temporary - until we have a proper HLT configuration source for the Run 3 trigger
-        ts.PriorityList = ["run3_dummy", 'xml']
-        rv.addService(ts)
-        return rv
-    rv.addService(DSConfigSvc('DSConfigSvc'))
-    tcs = SetupTrigConfigSvc()
-    # run3_dummy - temporary - until we have a proper HLT configuration source for the Run 3 trigger
-    tcs.SetStates(["run3_dummy", "ds"])
-    tcssvc = tcs.GetConfigurable()
-    rv.addService(tcssvc)
-
-    rv.merge(addFolders(flags, ['/TRIGGER/HLT/Menu',
-                                     '/TRIGGER/HLT/HltConfigKeys',
-                                     '/TRIGGER/LVL1/Lvl1ConfigKey',
-                                     '/TRIGGER/LVL1/Menu',
-                                     '/TRIGGER/LVL1/Prescales',
-                                     '/TRIGGER/LVL1/BunchGroupKey',
-                                     '/TRIGGER/LVL1/BunchGroupDescription',
-                                     '/TRIGGER/LVL1/BunchGroupContent',
-                                     '/TRIGGER/HLT/Prescales',
-                                     '/TRIGGER/HLT/PrescaleKey',
-                                     '/TRIGGER/LVL1/ItemDef'],
-                        'TRIGGER', tag='HEAD'))
-    
-    # the following should probably be set up by IOVDbSvc configuration?
-    rv.merge(TagInfoMgrCfg(flags)[0])
-    return rv
-
 def getTrigDecisionTool(flags):
     ''' Setup a TrigDecisionTool. Short-cuts deduplication with memoization.'''
     if getTrigDecisionTool.rv:
         return getTrigDecisionTool.rv
     from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator
-    from TrigDecisionTool.TrigDecisionToolConf import Trig__TrigDecisionTool
  
     rv = ComponentAccumulator()
 
@@ -75,17 +22,33 @@ def getTrigDecisionTool(flags):
         getTrigDecisionTool.rv = rv
         return getTrigDecisionTool.rv
 
-    rv.merge(getTrigConfigSvc(flags))
-    
-    tdt = Trig__TrigDecisionTool('TrigDecisionTool', TrigConfigSvc=rv.getService('TrigConfigSvc'))
+    from TrigConfxAOD.TrigConfxAODConf import TrigConf__xAODConfigTool
+    cfgtool = TrigConf__xAODConfigTool('xAODConfigTool')
+    rv.addPublicTool(cfgtool)
+
+    from TrigDecisionTool.TrigDecisionToolConf import Trig__TrigDecisionTool
+    tdt = Trig__TrigDecisionTool('TrigDecisionTool')
+    tdt.ConfigTool = cfgtool
+    tdt.NavigationFormat = "TrigComposite"
+    rv.addPublicTool(tdt)
+    # Other valid option of NavigationFormat is "TriggerElement" for Run 2 navigation. 
+    # This option to be removed and "TrigComposite" the only valid choice once a R2->R3 converter is put in place. 
+    # For now, it is assumed that any Run 2 AOD will be used with the legacy monitoring
+
     from TrigEDMConfig.TriggerEDM import EDMLibraries
     tdt.Navigation.Dlls = [e for e in  EDMLibraries if 'TPCnv' not in e]
-    
-    # Other valid option "TriggerElement" for Run 2 navigation. 
-    # This option to be removed and "TrigComposite" the only valid choice once a R2->R3 converter is put in place. 
-    tdt.NavigationFormat = "TrigComposite"
 
-    rv.addPublicTool(tdt)
+    # Minimal config needed to read metadata: MetaDataSvc & ProxyProviderSvc
+    from AthenaServices.AthenaServicesConf import MetaDataSvc
+    mdSvc = MetaDataSvc( "MetaDataSvc" )
+    mdSvc.MetaDataContainer = "MetaDataHdr"
+    rv.addService(mdSvc)
+
+    from SGComps.SGCompsConf import ProxyProviderSvc
+    pdps = ProxyProviderSvc( "ProxyProviderSvc" )
+    pdps.ProviderNames += [ "MetaDataSvc" ]
+    rv.addService(pdps)
+
     getTrigDecisionTool.rv = rv
     return rv
 getTrigDecisionTool.rv = None
diff --git a/HLT/Trigger/TrigControl/TrigExamples/TrigExPartialEB/python/MTCalibPebConfig.py b/HLT/Trigger/TrigControl/TrigExamples/TrigExPartialEB/python/MTCalibPebConfig.py
index 99de466efcdf8fccea0b0a58fc3ea895cc704433..a0eef6e400956caf4946efa218a3a63206471dc2 100644
--- a/HLT/Trigger/TrigControl/TrigExamples/TrigExPartialEB/python/MTCalibPebConfig.py
+++ b/HLT/Trigger/TrigControl/TrigExamples/TrigExPartialEB/python/MTCalibPebConfig.py
@@ -238,10 +238,6 @@ def configure_hlt_result(hypo_algs):
     # Tool adding HLT bits to HLT result
     bitsmaker = TriggerBitsMakerTool()
     bitsmaker.ChainDecisions = 'HLTNav_Summary'
-    bitsmaker.ChainToBit = {}
-    bitsmaker.ChainToBit['HLT_MTCalibPeb1'] = 3
-    bitsmaker.ChainToBit['HLT_MTCalibPeb2'] = 50
-    bitsmaker.ChainToBit['HLT_MTCalibPeb3'] = 11
 
     # Configure the HLT result maker to use the above tools
     from AthenaCommon.AppMgr import ServiceMgr as svcMgr
diff --git a/PhysicsAnalysis/PATJobTransforms/share/skeleton.PhysicsValidation_tf.py b/PhysicsAnalysis/PATJobTransforms/share/skeleton.PhysicsValidation_tf.py
index 805bd9872fe5cd7bd8fc43a6e0ecf97c3323ddfa..7c1b0dd8c6d60c630036379a5aad192a94fea4c6 100644
--- a/PhysicsAnalysis/PATJobTransforms/share/skeleton.PhysicsValidation_tf.py
+++ b/PhysicsAnalysis/PATJobTransforms/share/skeleton.PhysicsValidation_tf.py
@@ -150,12 +150,5 @@ if hasattr(runArgs,"postExec"):
 
 # Temporary (July 19) trigger additions
 if TriggerFlags.doMT() or TriggerFlags.EDMDecodingVersion() == 3:
-  ToolSvc.TrigDecisionTool.NavigationFormat="TrigComposite";
-  ToolSvc.TrigDecisionTool.TrigConfigSvc="Trig::TrigConfigSvc/TrigConfigSvc";
-  ServiceMgr.TrigConfigSvc.PriorityList=["run3_dummy", "xml"]
-  from TrigConfigSvc.TrigConfigSvcConfig import (findFileInXMLPATH,  LVL1ConfigSvc, L1TopoConfigSvc)
-  from AthenaConfiguration.AllConfigFlags import ConfigFlags
-  ServiceMgr += LVL1ConfigSvc("LVL1ConfigSvc")
-  ServiceMgr += L1TopoConfigSvc()
-  ServiceMgr.LVL1ConfigSvc.XMLMenuFile = findFileInXMLPATH(ConfigFlags.Trigger.LVL1ConfigFile.replace('newJO_', ''))
-  ServiceMgr.L1TopoConfigSvc.XMLMenuFile = findFileInXMLPATH(ConfigFlags.Trigger.LVL1TopoConfigFile)
\ No newline at end of file
+  if hasattr(ToolSvc, 'TrigDecisionTool'):
+    ToolSvc.TrigDecisionTool.NavigationFormat="TrigComposite"
diff --git a/Reconstruction/RecJobTransforms/share/skeleton.RDOtoRDOtrigger.py b/Reconstruction/RecJobTransforms/share/skeleton.RDOtoRDOtrigger.py
index 64488f961c7ae69f17ad6c3160d7001b267d6fbd..809f621921b9d8723d2f481cfa0c811d2253e14d 100644
--- a/Reconstruction/RecJobTransforms/share/skeleton.RDOtoRDOtrigger.py
+++ b/Reconstruction/RecJobTransforms/share/skeleton.RDOtoRDOtrigger.py
@@ -127,6 +127,10 @@ if TriggerFlags.doMT():
     from TrigConfigSvc.TrigConfigSvcCfg import getHLTConfigSvc
     svcMgr += getHLTConfigSvc()
 
+    from TrigConfigSvc.TrigConfigSvcConfig import TrigConfigSvc
+    svcMgr += TrigConfigSvc("TrigConfigSvc")
+    svcMgr.TrigConfigSvc.PriorityList = ["none", "ds", "xml"]
+
     from L1Decoder.L1DecoderConfig import L1Decoder
     topSequence += L1Decoder()
     
@@ -228,19 +232,20 @@ for i in outSequence.getAllChildren():
 
     if "StreamRDO" in i.getName() and TriggerFlags.doMT():
 
+        ### Produce the trigger bits:
+        from TrigOutputHandling.TrigOutputHandlingConf import TriggerBitsMakerTool
         from TrigDecisionMaker.TrigDecisionMakerConfig import TrigDecisionMakerMT
-        topSequence += TrigDecisionMakerMT('TrigDecMakerMT') # Replaces TrigDecMaker and finally deprecates Run 1 EDM
-        from AthenaCommon.Logging import logging
-        log = logging.getLogger( 'WriteTrigDecisionToAOD' )
-        log.info('TrigDecision writing enabled')
-
-        # Note: xAODMaker__TrigDecisionCnvAlg no longer needed. TrigDecisionMakerMT goes straight to xAOD
-        # Note: xAODMaker__TrigNavigationCnvAlg no longer needed. MT navigation is natively xAOD 
-        
-        # *** June 2019 TEMPORARY *** for use with TrigDecMakerMT until a proper config svc is available
-        from TrigConfigSvc.TrigConfigSvcConfig import TrigConfigSvc
-        ServiceMgr += TrigConfigSvc("TrigConfigSvc")
-        ServiceMgr.TrigConfigSvc.PriorityList = ["run3_dummy", "ds", "xml"]
+        bitsmakerTool = TriggerBitsMakerTool()
+        tdm = TrigDecisionMakerMT('TrigDecMakerMT') # Replaces TrigDecMaker and finally deprecates Run 1 EDM
+        tdm.BitsMakerTool = bitsmakerTool
+        topSequence += tdm
+        log.info('xTrigDecision writing enabled')
+
+        ### Produce the metadata:
+        from TrigConfxAOD.TrigConfxAODConf import TrigConf__xAODMenuWriterMT
+        md = TrigConf__xAODMenuWriterMT()
+        topSequence += md
+        log.info('TriggerMenu Metadata writing enabled')
 
         # Still need to produce Run-2 style L1 xAOD output
         topSequence += RoIBResultToAOD("RoIBResultToxAOD")
@@ -265,15 +270,15 @@ for i in outSequence.getAllChildren():
         StreamRDO.MetadataItemList +=  [ "xAOD::TriggerMenuContainer#*", "xAOD::TriggerMenuAuxContainer#*" ]
 
 from AthenaCommon.AppMgr import ServiceMgr, ToolSvc
-from TrigDecisionTool.TrigDecisionToolConf import *
+
 
 if hasattr(ToolSvc, 'TrigDecisionTool'):
     if TriggerFlags.doMT():
-        ToolSvc.TrigDecisionTool.NavigationFormat = "TrigComposite"
-        # To pick up hacked config svc
-        ToolSvc.TrigDecisionTool.TrigConfigSvc = "Trig::TrigConfigSvc/TrigConfigSvc"
+        # No functional TDT in MT in RDOtoRDOTrigger
+        pass
     else:
     	# Causes TDT to use Run-1 style behaviour in this part of the transform
+        from TrigDecisionTool.TrigDecisionToolConf import *
         ToolSvc.TrigDecisionTool.TrigDecisionKey = "TrigDecision"
         ToolSvc.TrigDecisionTool.UseAODDecision = True
 
diff --git a/Trigger/TrigAnalysis/TrigDecisionMaker/CMakeLists.txt b/Trigger/TrigAnalysis/TrigDecisionMaker/CMakeLists.txt
index 6e0bbf837320209a6efe5238cc734f109acdda1f..79e7588fe1f5f40e23245b5019414d4508a8c568 100644
--- a/Trigger/TrigAnalysis/TrigDecisionMaker/CMakeLists.txt
+++ b/Trigger/TrigAnalysis/TrigDecisionMaker/CMakeLists.txt
@@ -20,13 +20,14 @@ atlas_depends_on_subdirs( PRIVATE
                           Trigger/TrigEvent/TrigSteeringEvent
                           Trigger/TrigSteer/TrigSteering
                           Trigger/TrigSteer/DecisionHandling
+                          Trigger/TrigSteer/TrigOutputHandling
                           Trigger/TrigT1/TrigT1Result )
 
 # Component(s) in the package:
 atlas_add_component( TrigDecisionMaker
                      src/*.cxx
                      src/components/*.cxx
-                     LINK_LIBRARIES AthenaBaseComps DecisionHandlingLib StoreGateLib SGtests EventInfo xAODEventInfo GaudiKernel TrigConfL1Data TrigConfHLTData TrigDecisionEvent TrigSteeringEvent TrigSteeringLib TrigT1Result xAODTrigger )
+                     LINK_LIBRARIES AthenaBaseComps DecisionHandlingLib StoreGateLib SGtests EventInfo xAODEventInfo GaudiKernel TrigConfL1Data TrigConfHLTData TrigDecisionEvent TrigSteeringEvent TrigSteeringLib TrigT1Result xAODTrigger TrigOutputHandlingLib )
 
 # Install files from the package:
 atlas_install_python_modules( python/__init__.py python/TrigDecisionMakerConfig.py )
diff --git a/Trigger/TrigAnalysis/TrigDecisionMaker/src/TrigDecisionMakerMT.cxx b/Trigger/TrigAnalysis/TrigDecisionMaker/src/TrigDecisionMakerMT.cxx
index 9da4c6261782f6ec0d5dcee38e1628d2f2f61ffc..13c7e004f6ae773be32f26ee9094ac34de933f9d 100644
--- a/Trigger/TrigAnalysis/TrigDecisionMaker/src/TrigDecisionMakerMT.cxx
+++ b/Trigger/TrigAnalysis/TrigDecisionMaker/src/TrigDecisionMakerMT.cxx
@@ -27,6 +27,8 @@
 #include "TrigConfHLTData/HLTChainList.h"
 #include "TrigConfHLTData/HLTUtils.h"
 
+#include <boost/dynamic_bitset.hpp>
+
 using namespace TrigDec;
 
 TrigDecisionMakerMT::TrigDecisionMakerMT(const std::string &name, ISvcLocator *pSvcLocator)
@@ -39,7 +41,16 @@ TrigDecisionMakerMT::~TrigDecisionMakerMT() {}
 
 StatusCode TrigDecisionMakerMT::initialize()
 {
-  ATH_CHECK( m_HLTSummaryKeyIn.initialize() );
+
+  if (!m_bitsMakerTool.empty()) {
+    ATH_MSG_INFO("TrigDecisionMakerMT is setting up for MC to use the TriggerBitsMakerTool");
+    ATH_CHECK( m_bitsMakerTool.retrieve() );
+  } else {
+    ATH_MSG_INFO("TrigDecisionMakerMT is setting up for Data to use the HLTResultMT. "
+      "If this job is for MC, make sure that the BitsMakerTool property is set instead.");
+    ATH_CHECK( m_hltResultKeyIn.initialize() );
+  }
+
   ATH_CHECK( m_ROIBResultKeyIn.initialize() );
   ATH_CHECK( m_EventInfoKeyIn.initialize() );
 
@@ -75,98 +86,74 @@ StatusCode TrigDecisionMakerMT::execute(const EventContext& context) const
   // increment event counter
   m_nEvents++;
 
-  // Retrieve the results
-  const LVL1CTP::Lvl1Result* l1Result = nullptr;
+  std::unique_ptr<xAOD::TrigDecision>        trigDec    = std::make_unique<xAOD::TrigDecision>();
+  std::unique_ptr<xAOD::TrigDecisionAuxInfo> trigDecAux = std::make_unique<xAOD::TrigDecisionAuxInfo>();
+  trigDec->setStore(trigDecAux.get());
+
+  trigDec->setSMK( m_trigConfigSvc->masterKey() );
+
   if (m_doL1) {
+    const LVL1CTP::Lvl1Result* l1Result = nullptr;
     ATH_CHECK(getL1Result(l1Result, context));
+
+    trigDec->setTAV(l1Result->itemsAfterVeto());
+    trigDec->setTAP(l1Result->itemsAfterPrescale());
+    trigDec->setTBP(l1Result->itemsBeforePrescale());
+
     if (l1Result->isAccepted()) {
       ++m_l1Passed;
     }
   }
 
-  const DecisionContainer* hltResult = nullptr;
   if (m_doHLT) {
-    ATH_CHECK(getHLTResult(hltResult, context));
-  }
 
-  std::unique_ptr<xAOD::TrigDecision>        trigDec    = std::make_unique<xAOD::TrigDecision>();
-  std::unique_ptr<xAOD::TrigDecisionAuxInfo> trigDecAux = std::make_unique<xAOD::TrigDecisionAuxInfo>();
-  trigDec->setStore(trigDecAux.get());
+    boost::dynamic_bitset<uint32_t> passRawBitset, prescaledBitset, rerunBitset;
 
-  trigDec->setSMK( m_trigConfigSvc->masterKey() );
+    if (m_bitsMakerTool.isSet()) {
 
-  if (l1Result) {
-    trigDec->setTAV(l1Result->itemsAfterVeto());
-    trigDec->setTAP(l1Result->itemsAfterPrescale());
-    trigDec->setTBP(l1Result->itemsBeforePrescale());
-  }
+      ATH_MSG_DEBUG ("MC Mode: Creating bits with TriggerBitsMakerTool");
+      ATH_CHECK(m_bitsMakerTool->getBits(passRawBitset, prescaledBitset, rerunBitset, context));
 
-  // Output bitsets (stored in a vector<uint32_t>)
-  std::vector<uint32_t> hltPassBits;
-  std::vector<uint32_t> hltPrescaledBits;
-  std::vector<uint32_t> hltRerunBits;
-
-  std::set< std::vector<uint32_t>* > outputVectors;
-  outputVectors.insert( &hltPassBits );
-  outputVectors.insert( &hltPrescaledBits );
-  outputVectors.insert( &hltRerunBits );
-
-  if (hltResult) {
-    ATH_MSG_DEBUG("Got a DecisionContainer '" << m_HLTSummaryKeyIn.key() << "' of size " << hltResult->size());
-    const Decision* HLTPassRaw = nullptr;
-    const Decision* HLTPrescaled = nullptr;
-    const Decision* HLTRerun = nullptr;
-
-    DecisionIDContainer passRawInput; //!< The chains which returned a positive decision
-    DecisionIDContainer prescaledInput; //!< The chains which did not run due to being prescaled out
-    DecisionIDContainer rerunInput; //!< The chains which were activate only in the rerun (not physics decisions)
-
-    // Read the sets of chain IDs
-    for (const Decision* decisionObject : *hltResult) {
-      // Collect all decisions (IDs of passed/prescaled/rerun chains) from named decisionObjects
-      if (decisionObject->name() == "HLTPassRaw") {
-        HLTPassRaw = decisionObject;
-      } else if (decisionObject->name() == "HLTPrescaled") {
-        HLTPrescaled = decisionObject;
-      } else if (decisionObject->name() == "HLTRerun") {
-        HLTRerun = decisionObject;
-      }
-      if (HLTPassRaw && HLTPrescaled && HLTRerun) {
-        break;
-      }
-    }
+     } else {
 
-    ATH_CHECK(HLTPassRaw != nullptr);
-    ATH_CHECK(HLTPrescaled != nullptr);
-    ATH_CHECK(HLTRerun != nullptr);
+      ATH_MSG_DEBUG ("Data Mode: Reading bits from HLTResultMT");
+      SG::ReadHandle<HLT::HLTResultMT> hltResult = SG::makeHandle<HLT::HLTResultMT>(m_hltResultKeyIn, context);
+      ATH_CHECK(hltResult.isValid());
 
-    // Get all passed IDs.
-    decisionIDs(HLTPassRaw, passRawInput);
+      passRawBitset = hltResult->getHltPassRawBits();
+      prescaledBitset = hltResult->getHltPrescaledBits();
+      rerunBitset = hltResult->getHltRerunBits();
 
-    // Simpler structure for prescaled. 
-    decisionIDs(HLTPrescaled, prescaledInput);
+    }
 
-    // Get all passed IDs. 
-    decisionIDs(HLTRerun, rerunInput);   
+    ATH_MSG_DEBUG ("Number of HLT chains passed raw: " << passRawBitset.count());
+    ATH_MSG_DEBUG ("Number of HLT chains prescaled out: " << prescaledBitset.count());
+    ATH_MSG_DEBUG ("Number of HLT chains in rerun / second pass / resurrection : " << rerunBitset.count());
 
-    if (passRawInput.size()) {
+    if (passRawBitset.any()) {
       ++m_hltPassed;
     }
-  
-    // Make bitmap for passed raw
-    size_t countHltPass = makeBitMap(passRawInput, hltPassBits, outputVectors);
-    ATH_MSG_DEBUG ("Number of HLT chains passed raw: " << countHltPass);
-    trigDec->setEFPassedRaw(hltPassBits);
-
-    // Make bitmap for prescaled
-    size_t countHltPrescaled = makeBitMap(prescaledInput, hltPrescaledBits, outputVectors);
-    ATH_MSG_DEBUG ("Number of HLT chains prescaled out: " << countHltPrescaled);
-    trigDec->setEFPrescaled(hltPrescaledBits);
-
-    // Make bitmap for rerun a.k.a. resurrection
-    size_t countHLTRerun = makeBitMap(rerunInput, hltRerunBits, outputVectors);
-    ATH_MSG_DEBUG ("Number of HLT chains in rerun / second pass / resurrection : " << countHLTRerun);
-    trigDec->setEFResurrected(hltRerunBits);
+
+    std::vector<uint32_t> passRaw, prescaled, rerun;
+
+    passRaw.resize(passRawBitset.num_blocks());
+    prescaled.resize(prescaledBitset.num_blocks());
+    rerun.resize(rerunBitset.num_blocks());
+
+    boost::to_block_range(passRawBitset, passRaw.begin());
+    boost::to_block_range(prescaledBitset, prescaled.begin());
+    boost::to_block_range(rerunBitset, rerun.begin());
+
+    if (passRaw.size() != prescaled.size() or passRaw.size() != rerun.size()) {
+      ATH_MSG_ERROR("Trigger bitsets are not all the same size! passRaw:" 
+        << passRaw.size() << " prescaled:" << prescaled.size() << " rerun:" << rerun.size() );
+      return StatusCode::FAILURE;
+    } 
+
+    trigDec->setEFPassedRaw(passRaw);
+    trigDec->setEFPrescaled(prescaled);
+    trigDec->setEFResurrected(rerun);
+
   }
 
   // get the bunch crossing id
@@ -189,31 +176,24 @@ StatusCode TrigDecisionMakerMT::execute(const EventContext& context) const
 
 StatusCode TrigDecisionMakerMT::getL1Result(const LVL1CTP::Lvl1Result*& result, const EventContext& context) const
 {
-  const ROIB::RoIBResult* roIBResult = SG::get(m_ROIBResultKeyIn, context);
+  SG::ReadHandle<ROIB::RoIBResult> roIBResult = SG::makeHandle<ROIB::RoIBResult>(m_ROIBResultKeyIn, context);
+  ATH_CHECK(roIBResult.isValid());
 
   std::vector< std::unique_ptr<LVL1CTP::Lvl1Item> > itemConfig = m_lvl1Tool->makeLvl1ItemConfig();
 
-  if (roIBResult && (roIBResult->cTPResult()).isComplete()) {  
+  if (roIBResult->cTPResult().isComplete()) {
     m_lvl1Tool->createL1Items(itemConfig, *roIBResult, &result);
     ATH_MSG_DEBUG ( "Built LVL1CTP::Lvl1Result from valid CTPResult.");
   }
 
   if (result == nullptr) {
-    ATH_MSG_DEBUG ( "Could not construct L1 result from roIBResult");
+    ATH_MSG_ERROR ( "Could not construct L1 result from roIBResult");
     return StatusCode::FAILURE;
   }
 
   return StatusCode::SUCCESS;
 }
 
-
-StatusCode TrigDecisionMakerMT::getHLTResult(const TrigCompositeUtils::DecisionContainer*& result, const EventContext& context) const
-{
-  result = SG::get(m_HLTSummaryKeyIn, context);
-  return StatusCode::SUCCESS;
-}
-
-
 char TrigDecisionMakerMT::getBGByte(int BCId) const {
   const TrigConf::BunchGroupSet* bgs = m_trigConfigSvc->bunchGroupSet();
   if (!bgs) {
@@ -226,55 +206,3 @@ char TrigDecisionMakerMT::getBGByte(int BCId) const {
   }
   return bgs->bgPattern()[BCId];  
 }
-
-
-size_t TrigDecisionMakerMT::makeBitMap(
-  const TrigCompositeUtils::DecisionIDContainer& passedIDs,
-  std::vector<uint32_t>& bitsVector,
-  std::set< std::vector<uint32_t>* >& allOutputVectors) const
-{
-  size_t count = 0;
-  for (const TrigCompositeUtils::DecisionID id : passedIDs) {
-    const int32_t chainCounter = getChainCounter(id);
-    if (chainCounter == -1) continue; // Could not decode, prints error
-    resizeVectors(chainCounter, allOutputVectors); // Make sure we have enough room to be able to set the required bit
-    setBit(chainCounter, bitsVector);
-    ++count;
-  }
-  return count;
-}
-
-
-void TrigDecisionMakerMT::resizeVectors(const size_t bit, const std::set< std::vector<uint32_t>* >& vectors) const {
-  const size_t block = bit / std::numeric_limits<uint32_t>::digits;
-  const size_t requiredSize = block + 1;
-  if (vectors.size() && requiredSize > (*vectors.begin())->size()) {
-    for (std::vector<uint32_t>* vecPtr : vectors) {
-      vecPtr->resize(requiredSize, 0); // Resize can shrink, here we only ever want to expand
-    }
-  }
-  return;
-}
-
-
-void TrigDecisionMakerMT::setBit(const size_t bit, std::vector<uint32_t>& bits) const {
-  const size_t block = bit / std::numeric_limits<uint32_t>::digits; // = 32
-  const size_t offset = bit % std::numeric_limits<uint32_t>::digits;
-  bits.at(block) |= static_cast<uint32_t>(1) << offset;
-}
-
-
-int32_t TrigDecisionMakerMT::getChainCounter(const TrigCompositeUtils::DecisionID chainID) const {
-  // Need to go from hash-ID to chain-counter. HLTChain counter currently does not give this a category
-  const std::string chainName = TrigConf::HLTUtils::hash2string(chainID);
-  if (chainName == "UNKNOWN HASH ID" || chainName == "UNKNOWN CATEGORY") {
-    ATH_MSG_ERROR("Unable to locate chain with hashID:" << chainID << " in the TrigConf, the error reported was: " << chainName);
-    return -1;
-  }
-  const TrigConf::HLTChain* chain = m_trigConfigSvc->chains().chain(chainName);
-  if (chain == nullptr) {
-    ATH_MSG_ERROR("Unable to fetch HLTChain object for chain with hashID:" << chainID << " and name:'" << chainName << "' (number of chains:" << m_trigConfigSvc->chains().size() << ")");
-    return -1;        
-  }
-  return chain->chain_counter();
-}
diff --git a/Trigger/TrigAnalysis/TrigDecisionMaker/src/TrigDecisionMakerMT.h b/Trigger/TrigAnalysis/TrigDecisionMaker/src/TrigDecisionMakerMT.h
index 4f6d53731dc05283ed42e38771648d41a55a7c4b..6b3e3779a187ad4f44c16b8c5a53a4d8cad5fd65 100644
--- a/Trigger/TrigAnalysis/TrigDecisionMaker/src/TrigDecisionMakerMT.h
+++ b/Trigger/TrigAnalysis/TrigDecisionMaker/src/TrigDecisionMakerMT.h
@@ -30,10 +30,10 @@
 #include "xAODEventInfo/EventInfo.h"
 
 // trigger/configuration stuff
-#include "xAODTrigger/TrigCompositeContainer.h"
 #include "xAODTrigger/TrigDecision.h"
-#include "DecisionHandling/TrigCompositeUtils.h"
 #include "TrigT1Result/RoIBResult.h"
+#include "TrigSteeringEvent/HLTResultMT.h"
+#include "TrigOutputHandling/ITriggerBitsMakerTool.h"
 
 // containers
 #include <vector>
@@ -79,41 +79,12 @@ namespace TrigDec {
     virtual StatusCode execute( const EventContext& context ) const override; //!< Re-entrant execute to create the xAOD::TrigDecision
     virtual StatusCode finalize() override;    //!< std Gaudi finalize method -> print out statistics
 
+  private:
+
     StatusCode getL1Result (const LVL1CTP::Lvl1Result*& result, const EventContext& context) const; //!< retrieve LVL1 result (called in execute)
-    StatusCode getHLTResult(const TrigCompositeUtils::DecisionContainer*& result, const EventContext& context) const; //!< retrieve HLT results (called in execute)
 
     char getBGByte(int BCId) const; //!< to get the BG byte encoded for a given BC
 
-  private:
-
-    /**
-     * @brief Ensures that the supplied vectors have sufficient capacity to store the given bit, where bits are packed into uint32_t.
-     * @param bit The bit we wish the vectors to be large enough to store
-     * @param vectors Set of pointers to all vectors which need resizing. Note, while the set of pointers is const, the vectors are not const.
-     **/  
-    void resizeVectors(const size_t bit, const std::set< std::vector<uint32_t>* >& vectors) const;
-
-    /**
-     * @param bit The bit to set to 1 (bit 0 equates to the first bit). Requires the vector to have already been resized to be large enough.
-     * @param bits The vector to set the bit in.
-     **/
-    void setBit(const size_t bit, std::vector<uint32_t>& bits) const;
-
-    /**
-     * @param chainID The identifier (name hash) of the chain to fetch the ChainCounter for.
-     * @return the Chain Counter or -1 if error.
-     **/
-    int32_t getChainCounter(const TrigCompositeUtils::DecisionID chainID) const;
-
-    /**
-     * @param passedIDs Set of IDs of passed chains.
-     * @param bitsVector Vector to set passed-bits in based off of passedIDs
-     * @param allOutputVectors Set of pointers to *all* output vectors, keeps them all the same size
-     * @return the number of positive bits set in the vector, should be the same as passedIDs.size()
-     **/
-    size_t makeBitMap(const TrigCompositeUtils::DecisionIDContainer& passedIDs,
-      std::vector<uint32_t>& bitsVector, std::set< std::vector<uint32_t>* >& allOutputVectors) const;
-
     Gaudi::Property<bool> m_doL1{this, "doL1",  true, "Read L1 trigger information"};
     Gaudi::Property<bool> m_doHLT{this, "doHLT", true, "Read HLT trigger information"};
 
@@ -124,8 +95,10 @@ namespace TrigDec {
     ToolHandle<HLT::ILvl1ResultAccessTool> m_lvl1Tool;  //!< tool to ease the access to the L1 results (RoIs, items, etc)
     Gaudi::Property<std::string> m_lvl1ToolLocation{this, "Lvl1ToolLocation", "HLT::Lvl1ResultAccessTool/Lvl1ResultAccessTool", "L1 tool to fetch"};
 
+    ToolHandle<ITriggerBitsMakerTool> m_bitsMakerTool{this, "BitsMakerTool", "", "Tool to create trigger bits for MC"};
+
     // Input keys configuration
-    SG::ReadHandleKey<TrigCompositeUtils::DecisionContainer> m_HLTSummaryKeyIn {this, "HLTSummary", "HLTNav_Summary", "HLT summary container Key"};
+    SG::ReadHandleKey<HLT::HLTResultMT> m_hltResultKeyIn {this, "HLTResultMT", "HLTResultMT", "Key of the HLTResultMT object to get bits from online bytestream" };
     SG::ReadHandleKey<LVL1CTP::Lvl1Result> m_L1ResultKeyIn {this, "Lvl1Result", "Lvl1Result", "Lvl1 Result Object Key"};
     SG::ReadHandleKey<ROIB::RoIBResult> m_ROIBResultKeyIn {this, "RoIBResult", "RoIBResult", "RoIB Result Object Key"};
     SG::ReadHandleKey<xAOD::EventInfo> m_EventInfoKeyIn {this, "EventInfo", "EventInfo", "Event Info Object Key"};
diff --git a/Trigger/TrigAnalysis/TrigDecisionTool/Root/TrigDecisionTool.cxx b/Trigger/TrigAnalysis/TrigDecisionTool/Root/TrigDecisionTool.cxx
index 140e78922e4c05e67151496dd4bb35a7a95ad446..2e755b1b36e01df6d0a17aaa032f04af8b6b0756 100644
--- a/Trigger/TrigAnalysis/TrigDecisionTool/Root/TrigDecisionTool.cxx
+++ b/Trigger/TrigAnalysis/TrigDecisionTool/Root/TrigDecisionTool.cxx
@@ -145,11 +145,12 @@ Trig::TrigDecisionTool::initialize() {
      }
    }
 
-
-   StatusCode sc = m_fullNavigation.retrieve();
-   if ( sc.isFailure() ) {
-     ATH_MSG_FATAL( "Unable to get Navigation tool");
-     return sc;
+   if (m_navigationFormat == "TriggerElement") {
+     StatusCode sc = m_fullNavigation.retrieve();
+     if ( sc.isFailure() ) {
+       ATH_MSG_FATAL( "Unable to get Navigation tool");
+       return sc;
+     }
    }
 #else
    ATH_CHECK(m_configTool.retrieve());
diff --git a/Trigger/TrigConfiguration/TrigConfData/TrigConfData/HLTChain.h b/Trigger/TrigConfiguration/TrigConfData/TrigConfData/HLTChain.h
index 2c1b415a1335694be866785de29061ba68c6c7e8..79d1aa137cc102a7ca4a26e3d9d4f0883aa3c30c 100644
--- a/Trigger/TrigConfiguration/TrigConfData/TrigConfData/HLTChain.h
+++ b/Trigger/TrigConfiguration/TrigConfData/TrigConfData/HLTChain.h
@@ -38,6 +38,12 @@ namespace TrigConf {
        */
       unsigned int counter() const;
 
+      /** Accessor to the chain name hash
+       *
+       * The hash is unique within the menu and identifies the chain online
+       */
+      unsigned int namehash() const;
+
       /** Accessor to the seeding L1 item */
       const std::string & l1item() const;
 
diff --git a/Trigger/TrigConfiguration/TrigConfData/src/HLTChain.cxx b/Trigger/TrigConfiguration/TrigConfData/src/HLTChain.cxx
index 4cf60305df3f7403e1ce7b86cabb3f544e991b27..6ecf08ba166fbd577cc916d0ded3cefd6ac48f8e 100644
--- a/Trigger/TrigConfiguration/TrigConfData/src/HLTChain.cxx
+++ b/Trigger/TrigConfiguration/TrigConfData/src/HLTChain.cxx
@@ -27,6 +27,12 @@ TrigConf::Chain::counter() const
    return m_data.get_child("counter").get_value<unsigned int>();
 }
 
+unsigned int
+TrigConf::Chain::namehash() const
+{
+   return m_data.get_child("nameHash").get_value<unsigned int>();
+}
+
 const std::string &
 TrigConf::Chain::l1item() const
 {
diff --git a/Trigger/TrigConfiguration/TrigConfData/src/L1Item.cxx b/Trigger/TrigConfiguration/TrigConfData/src/L1Item.cxx
index a495626f1778eb90eb0b96c5836a2164d65cfab4..ae3794b4ff84d61de9e36c34feb8515cfb609f17 100644
--- a/Trigger/TrigConfiguration/TrigConfData/src/L1Item.cxx
+++ b/Trigger/TrigConfiguration/TrigConfData/src/L1Item.cxx
@@ -23,7 +23,7 @@ TrigConf::L1Item::name() const
 unsigned int
 TrigConf::L1Item::ctpId() const
 {
-   return m_data.get_child("ctpId").get_value<unsigned int>();
+   return m_data.get_child("ctpid").get_value<unsigned int>();
 }
 
 const std::string &
diff --git a/Trigger/TrigConfiguration/TrigConfData/src/L1Menu.cxx b/Trigger/TrigConfiguration/TrigConfData/src/L1Menu.cxx
index 361a7d2bd74f78f64e9e0fa7a50c86b4f24157c0..4faf5fdb8ae213ca347d9a7df09c56f5d7938c52 100644
--- a/Trigger/TrigConfiguration/TrigConfData/src/L1Menu.cxx
+++ b/Trigger/TrigConfiguration/TrigConfData/src/L1Menu.cxx
@@ -38,23 +38,19 @@ TrigConf::L1Menu::ctpVersion() const
 std::size_t 
 TrigConf::L1Menu::size() const
 {
-   try {
-      return m_data.get_child("menu.items").size();
-   } catch(boost::property_tree::ptree_bad_path &) {
-      return m_data.get_child("items").size();
-   }
+   return m_data.get_child("items").size();
 }
 
 TrigConf::L1Menu::const_iterator
 TrigConf::L1Menu::begin() const
 {
-   return {m_data.get_child("menu.items"), 0,  [](auto x){return L1Item(x.second);}};
+   return {m_data.get_child("items"), 0,  [](auto x){return L1Item(x.second);}};
 }
 
 TrigConf::L1Menu::const_iterator
 TrigConf::L1Menu::end() const
 {
-   const auto & items = m_data.get_child("menu.items");
+   const auto & items = m_data.get_child("items");
    return {items, items.size(), [](auto x){return L1Item(x.second);}};
 }
 
diff --git a/Trigger/TrigConfiguration/TrigConfigSvc/python/TrigConfigSvcCfg.py b/Trigger/TrigConfiguration/TrigConfigSvc/python/TrigConfigSvcCfg.py
index 744b7b91ba0693373bf8ec3a6d02c3a0f5b2b320..e50d6ee4d1700804a07470e452d5ea025a61c8c8 100644
--- a/Trigger/TrigConfiguration/TrigConfigSvc/python/TrigConfigSvcCfg.py
+++ b/Trigger/TrigConfiguration/TrigConfigSvc/python/TrigConfigSvcCfg.py
@@ -87,7 +87,7 @@ def getHLTConfigSvc( flags = None ):
     from AthenaCommon.AppMgr import theApp
     hltConfigSvc = TrigConf__HLTConfigSvc( "HLTConfigSvc" )
     hltXMLFile = "None"
-    hltConfigSvc.ConfigSource = "Run3_Dummy"
+    hltConfigSvc.ConfigSource = "None"
     hltConfigSvc.XMLMenuFile = hltXMLFile
     hltConfigSvc.InputType = "file"
     hltJsonFileName = getHLTMenuFileName( flags )
diff --git a/Trigger/TrigConfiguration/TrigConfigSvc/python/TrigConfigSvcConfig.py b/Trigger/TrigConfiguration/TrigConfigSvc/python/TrigConfigSvcConfig.py
index 2610e129441328aa5755287b31f9f7f9ff9946a0..8d89892dc8e94795fff02121ca0cc10044e0e363 100755
--- a/Trigger/TrigConfiguration/TrigConfigSvc/python/TrigConfigSvcConfig.py
+++ b/Trigger/TrigConfiguration/TrigConfigSvc/python/TrigConfigSvcConfig.py
@@ -301,10 +301,10 @@ class SetupTrigConfigSvc(object):
             """
             state == xml -> read the trigger configuration from 2 xml files, one for L1, one for HLT
             stats == ds  -> read the trigger configuration from the detector store = esd header
-            state == run3_dummy -> use a hard-coded list of HLT chains until the HLT JSON is ready
+            state == none -> service is not directly serving the run3 configuration
             """
             self.states = ["xml"]
-            self.allowedStates = set(['run3_dummy','xml','ds'])
+            self.allowedStates = set(['none','xml','ds'])
             self.initialised = False
 
             from AthenaCommon.Logging import logging
diff --git a/Trigger/TrigConfiguration/TrigConfigSvc/src/ConfigSvcBase.cxx b/Trigger/TrigConfiguration/TrigConfigSvc/src/ConfigSvcBase.cxx
index 108c262584b3cd984472a2eb92e8edac394ca976..0dc5122f8e3af9c49a5ccfaaccc7cf6f2a8ce345 100644
--- a/Trigger/TrigConfiguration/TrigConfigSvc/src/ConfigSvcBase.cxx
+++ b/Trigger/TrigConfiguration/TrigConfigSvc/src/ConfigSvcBase.cxx
@@ -27,7 +27,7 @@ ConfigSvcBase::~ConfigSvcBase()
 void
 ConfigSvcBase::declareCommonProperties() {
    declareProperty( "ConfigSource",     m_configSourceString,
-                    "Source of trigger configuration; can be \"XML\", \"MySQL\", \"Oracle\", \"DBLookup\" or \"RUN3_DUMMY\" ");
+                    "Source of trigger configuration; can be \"XML\", \"MySQL\", \"Oracle\", \"DBLookup\", or \"none\"");
    declareProperty( "XMLMenuFile",      m_xmlFile,
                     "XML file containing the trigger configuration.");
    declareProperty( "DBServer",         m_dbServer,
@@ -63,8 +63,6 @@ ConfigSvcBase::initialize() {
    if (s == "none") {
       ATH_MSG_INFO("Old style menu has been disabled");
       m_xmlFile = "";
-   } else if (s == "run3_dummy") {
-      ATH_MSG_WARNING("Configured to use Run-3 Dummy menu. This should never be seen in production");
    } else if(s != "xml") {
       TrigDBConnectionConfig::DBType dbtype(TrigDBConnectionConfig::DBLookup);
       if (s == "oracle") { dbtype = TrigDBConnectionConfig::Oracle; }
diff --git a/Trigger/TrigConfiguration/TrigConfigSvc/src/HLTConfigSvc.cxx b/Trigger/TrigConfiguration/TrigConfigSvc/src/HLTConfigSvc.cxx
index 217a28293e2e6f2c4dfdd91de0ce1234d83ec8ac..b805767a855681febc527cb191a0330c60962523 100644
--- a/Trigger/TrigConfiguration/TrigConfigSvc/src/HLTConfigSvc.cxx
+++ b/Trigger/TrigConfiguration/TrigConfigSvc/src/HLTConfigSvc.cxx
@@ -182,7 +182,7 @@ HLTConfigSvc::initialize() {
             m_inputType = "db";
             m_smk = joSvc->superMasterKey();
             m_dbConnection = joSvc->server();
-            m_configSourceString = "RUN3_Dummy";
+            m_configSourceString = "none";
          }
       } else {
          ATH_MSG_INFO("Did not locate TrigConf::JobOptionsSvc, not running athenaHLT");
@@ -196,141 +196,8 @@ HLTConfigSvc::initialize() {
 
    ATH_CHECK(ConfigSvcBase::initialize());
 
-
-   //////////////////////////////////////////////////////////////
-   // BEGIN RUN-3 TESTING BLOCK - THIS SHOULD BE TEMPORARY
-   //////////////////////////////////////////////////////////////
-   string s(boost::to_lower_copy(m_configSourceString)); // lower case
-   if (s == "run3_dummy") {
-      std::map<std::string, std::string> dummyChains;
-      dummyChains["HLT_e3_etcut1step_L1EM3"] = "L1_EM3";
-      dummyChains["HLT_e3_etcut_L1EM3"] = "L1_EM3";
-      dummyChains["HLT_e3_etcut_mu6_L1EM8I_MU10"] = "L1_EM8I_MU10";
-      dummyChains["HLT_e5_etcut_L1EM3"] = "L1_EM3";
-      dummyChains["HLT_e7_etcut_L1EM3"] = "L1_EM3";
-      dummyChains["HLT_g5_etcut_L1EM3"] = "L1_EM3";
-      dummyChains["HLT_g5_etcut_LArPEB_L1EM3"] = "L1_EM3";
-      dummyChains["HLT_g20_etcut_LArPEB_L1EM15"] = "L1_EM15";
-      dummyChains["HLT_g10_etcut_L1EM7"] = "L1_EM7";
-      dummyChains["HLT_g15_etcut_L1EM12"] = "L1_EM12";
-      dummyChains["HLT_mu6_L1MU6"] = "L1_MU6";
-      dummyChains["HLT_mu6Comb_L1MU6"] = "L1_MU6";
-      dummyChains["HLT_2mu6Comb_L1MU6"] = "L1_MU6";
-      dummyChains["HLT_mu8_L1MU6"] = "L1_MU6";
-      dummyChains["HLT_mu10_L1MU10"] = "L1_MU10";
-      dummyChains["HLT_mu20_L1MU20"] = "L1_MU20";
-      dummyChains["HLT_j85_L1J20"] = "L1_J20";
-      dummyChains["HLT_j100_L1J20"] = "L1_J20";
-      // from egamma test
-      dummyChains["HLT_2e17_etcut_L12EM15VH"] = "L1_2EM15VH";
-      dummyChains["HLT_2e3_etcut"] = "L1_2EM3";
-      dummyChains["HLT_2e3_etcut_L12EM3"] = "L1_2EM3";
-      dummyChains["HLT_2g35_etcut_L12EM20VH"] = "L1_2EM20VH";
-      dummyChains["HLT_e26_etcut_L1EM22VHI"] = "L1_EM22VHI";
-      dummyChains["HLT_e3_e5_etcut"] = "L1_2EM3";
-      dummyChains["HLT_e3_etcut"] = "L1_EM3";
-      dummyChains["HLT_e3_etcut_L1EM3"] = "L1_EM3";
-      dummyChains["HLT_e5_etcut"] = "L1_EM3";
-      dummyChains["HLT_e5_etcut_L1EM3"] = "L1_EM3";
-      dummyChains["HLT_e7_etcut"] = "L1_EM7";
-      dummyChains["HLT_e7_etcut_L1EM3"] = "L1_EM3";
-      dummyChains["HLT_g140_etcut_L1EM24VHI"] = "L1_EM24VHI";
-      dummyChains["HLT_g5_etcut_L1EM3"] = "L1_EM3";
-      // for menu test
-      dummyChains["HLT_2j330_a10t_lcw_jes_35smcINF_L1J100"] = "L1_J100";
-      dummyChains["HLT_j460_a10t_lcw_jes_30smcINF_L1J100"] = "L1_J100";
-      dummyChains["HLT_mu26_ivarmedium_L1MU20"] = "L1_MU20";
-      dummyChains["HLT_mu50_L1MU20"] = "L1_MU20";
-      dummyChains["HLT_mu50_RPCPEBSecondaryReadout_L1MU20"] = "L1_MU20";
-      dummyChains["HLT_2mu14_L12MU10"] = "L1_2MU10";
-      dummyChains["HLT_j420_L1J100"] = "L1_J100";
-      dummyChains["HLT_j260_320eta490_L1J75_31ETA49"] = "L1_J75.31ETA49";
-      dummyChains["HLT_j460_a10r_L1J100"] = "L1_J100";
-      dummyChains["HLT_j460_a10_lcw_subjes_L1J100"] = "L1_J100";
-      dummyChains["HLT_j460_a10t_lcw_jes_L1J100"] = "L1_J100";
-      dummyChains["HLT_3j200_L1J100"] = "L1_J100";
-      dummyChains["HLT_tau160_mediumRNN_tracktwoMVA_L1TAU100"] = "L1_TAU100";
-      dummyChains["HLT_2mu4_bBmumu_L12MU4"] = "L1_2MU4";
-      dummyChains["HLT_2mu4_bDimu_L12MU4"] = "L1_2MU4";
-      dummyChains["HLT_2mu4_bJpsimumu_L12MU4"] = "L1_2MU4";
-      dummyChains["HLT_2mu4_bUpsimumu_L12MU4"] = "L1_2MU4";
-      dummyChains["HLT_2mu6_L12MU6"] = "L1_2MU6";
-      dummyChains["HLT_2mu6Comb_L12MU6"] = "L1_2MU6";
-      dummyChains["HLT_2mu6_bJpsimumu_L12MU6"] = "L1_2MU6";
-      dummyChains["HLT_2mu6_10invm70_L1MU6"] = "L1_2MU6";
-      dummyChains["HLT_3j200_L1J20"] = "L1_J20";
-      dummyChains["HLT_5j70_0eta240_L14J20"] = "L1_4J20";
-      dummyChains["HLT_e3_etcut1step_mu6fast_L1EM8I_MU10"] = "L1_EM8I_MU10";
-      dummyChains["HLT_e3_etcut_mu6"] = "L1_EM8I_MU10";
-      dummyChains["HLT_g5_etcut"] = "L1_EM3";
-      dummyChains["HLT_j0_vbenfSEP30etSEP34mass35SEP50fbet_L1J20"] = "L1_L1J20";
-      dummyChains["HLT_j225_gsc420_boffperf_split20"] = "L1_J100";
-      dummyChains["HLT_j260_320eta490_L1J20"] = "L1_J20";
-      dummyChains["HLT_j420_L1J20"] = "L1_J20";
-      dummyChains["HLT_j45_L1J15"] = "L1_J15";
-      dummyChains["HLT_j80_j60_L1J15"] = "L1_J15";
-      dummyChains["HLT_j80_0eta240_2j60_320eta490_j0_dijetSEP80j1etSEP0j1eta240SEP80j2etSEP0j2eta240SEP700djmass_L1J20"] = "L1_J20";
-      dummyChains["HLT_j460_a10_lcw_subjes_L1J20"] = "L1_J20";
-      dummyChains["HLT_j460_a10r_L1J20"] = "L1_J20";
-      dummyChains["HLT_mu20_ivar_L1MU6"] = "L1_MU6";
-      dummyChains["HLT_mu6"] = "L1_MU6";
-      dummyChains["HLT_mu6_ivarmedium_L1MU6"] = "L1_MU6";
-      dummyChains["HLT_mu6Comb"] = "L1_MU6";
-      dummyChains["HLT_mu6fast_L1MU6"] = "L1_MU6";
-      dummyChains["HLT_mu6_msonly_L1MU6"] = "L1_MU6";
-      dummyChains["HLT_mu6noL1_L1MU6"] = "L1_MU6";
-      dummyChains["HLT_mu6_mu6noL1_L1MU6"] = "L1_MU6";
-      dummyChains["HLT_mu6_mu4_L12MU4"] = "L1_2MU4";
-      dummyChains["HLT_mu80_msonly_3layersEC_L1MU20"] = "L1_MU20";
-      dummyChains["HLT_mu10_lateMu_L1MU10"] = "L1_MU10";
-      dummyChains["HLT_xe30_cell_L1XE10"] = "L1_XE10";
-      dummyChains["HLT_xe30_tcpufit_L1XE10"] = "L1_XE10";
-      dummyChains["HLT_xe65_cell_L1XE50"] = "L1_XE510";
-      dummyChains["HLT_xe65_cell_L1XE50"] = "L1_XE510";
-      dummyChains["HLT_tau0_perf_ptonly_L1TAU12"] = "L1_TAU12";
-      dummyChains["HLT_tau25_medium1_tracktwo_L1TAU12IM"] = "L1_TAU12IM";
-      dummyChains["HLT_tau35_mediumRNN_tracktwoMVA_L1TAU12IM"] = "L1_TAU12IM";
-      dummyChains["HLT_j35_gsc45_boffperf_split_L1J20"] = "L1_J20";
-      dummyChains["HLT_j35_gsc45_bmv2c1070_split_L1J20"] = "L1_J20";
-      dummyChains["HLT_xe30_cell_xe30_tcpufit_L1XE10"] = "L1_XE10";
-      dummyChains["HLT_xe30_mht_L1XE10"] = "L1_XE10";
-      dummyChains["HLT_mu60_0eta105_msonly_L1MU20"] = "L1_MU20";
-      dummyChains["HLT_3mu6_L13MU6"] = "L1_3MU6";
-      dummyChains["HLT_3mu6_msonly_L13MU6"] = "L1_3MU6";
-      dummyChains["HLT_4mu4_L14MU4"] = "L1_4MU4";
-      dummyChains["HLT_j175_gsc225_bmv2c1040_split_L1J100"] = "L1_J100";
-      dummyChains["HLT_j225_gsc275_bmv2c1060_split_L1J100"] = "L1_J100";
-      dummyChains["HLT_j225_gsc300_bmv2c1070_split_L1J100"] = "L1_J100";
-      dummyChains["HLT_j225_gsc360_bmv2c1077_split_L1J100"] = "L1_J100";
-      dummyChains["HLT_tau160_mediumRNN_tracktwoMVA_L1TAU100"] = "L1_TAU100";
-      dummyChains["HLT_2mu10_bJpsimumu_L12MU10"] = "L1_2MU10";
-      dummyChains["HLT_2mu10_bUpsimumu_L12MU10"] = "L1_2MU10";
-      // ATR-19985
-      dummyChains["HLT_mu6_idperf_L1MU6"] = "L1_MU6";
-      dummyChains["HLT_mu24_idperf_L1MU20"] = "L1_MU20";
-      dummyChains["HLT_tau25_idperf_tracktwo_L1TAU12IM"] = "L1_TAU12IM";
-      dummyChains["HLT_tau25_idperf_tracktwoEF_L1TAU12IM"] = "L1_TAU12IM";
-      dummyChains["HLT_tau25_idperf_tracktwoMVA_L1TAU12IM"] = "L1_TAU12IM";
-      dummyChains["HLT_costmonitor_CostMonDS_L1TE5"] = "L1_TE5";
-
-      m_HLTFrame.setMergedHLT( m_setMergedHLT );
-      for (const auto& mapPair : dummyChains) {
-         const std::string& chainName = mapPair.first;
-         const std::string& chainSeed = mapPair.second;
-         const int chainCounter = std::distance(dummyChains.begin(), dummyChains.find(chainName));
-         HLTChain* chain = new HLTChain( chainName, chainCounter, 1, "HLT", chainSeed, 0, vector<HLTSignature*>() );
-         // Note: the ownership of chain is transfered to the frame, the frame will delete it on deconstruct.
-         m_HLTFrame.theHLTChainList().addHLTChain( chain );
-         ATH_MSG_INFO(" RUN 3 TESTING MODE! Adding dummy chain with hash:" << chain->chain_hash_id() << " : " << chainName << " [" << chainCounter << "] <- " << chainSeed); 
-      }
-      ATH_MSG_INFO(" RUN 3 TESTING MODE! Total number of chains: " << m_HLTFrame.chains().size()); 
-
-      return StatusCode::SUCCESS;
-
-   //////////////////////////////////////////////////////////////
-   // END RUN-3 TESTING BLOCK - THIS SHOULD BE TEMPORARY
-   //////////////////////////////////////////////////////////////
-   } else if( !fromDB() and m_xmlFile=="NONE" ) {
+   std::string xmlFile(boost::to_lower_copy(m_xmlFile)); // lower case
+   if( !fromDB() and (xmlFile=="none" or xmlFile == "")) {
       ATH_MSG_INFO("xml file set to NONE, will not load HLT Menu");
       return StatusCode::SUCCESS;
    }
diff --git a/Trigger/TrigConfiguration/TrigConfigSvc/src/TrigConfigSvc.cxx b/Trigger/TrigConfiguration/TrigConfigSvc/src/TrigConfigSvc.cxx
index 9b01a28e6953df3a18b8932d481b3f2610216537..69ff75ed25defbaa0288236d2dc1f7686f12ee13 100644
--- a/Trigger/TrigConfiguration/TrigConfigSvc/src/TrigConfigSvc.cxx
+++ b/Trigger/TrigConfiguration/TrigConfigSvc/src/TrigConfigSvc.cxx
@@ -52,23 +52,17 @@ TrigConfigSvc::initialize() {
 
       ATH_MSG_INFO("    => " << testsvc);
 
-      //////////////////////////////////////////////////////////////
-      // BEGIN RUN-3 TESTING BLOCK - THIS SHOULD BE TEMPORARY
-      ////////////////////////////////////////////////////////////// 
-      if ( testsvc == "run3_dummy" ) {
+      if ( testsvc == "none" ) {
          ATH_CHECK( AAH::setProperty( m_hltSvc, "ConfigSource", testsvc ) );
          if (m_hltSvc.retrieve().isSuccess()) {
             m_hltservice = m_hltSvc.operator->();
-            ATH_MSG_WARNING("Got HLT Svc " << m_hltSvc.typeAndName() << ", will use R3 dummy menu");
+            ATH_MSG_WARNING("Got HLT Svc " << m_hltSvc.typeAndName() << ", will not serve configuration via this service");
             hltfromxml = true;
          } else {
-            ATH_MSG_FATAL("failed to retrieve HLT ConfigSvc: " << m_hltSvc << " using R3 dummy menu");
+            ATH_MSG_FATAL("failed to retrieve HLT ConfigSvc: " << m_hltSvc << " with source 'none'");
             return StatusCode::FAILURE;
          }
       }
-      //////////////////////////////////////////////////////////////
-      // END RUN-3 TESTING BLOCK - THIS SHOULD BE TEMPORARY
-      ////////////////////////////////////////////////////////////// 
 
       if ( testsvc == "ds" ) {
          if (m_dsSvc.retrieve().isSuccess()) {
diff --git a/Trigger/TrigConfiguration/TrigConfxAOD/CMakeLists.txt b/Trigger/TrigConfiguration/TrigConfxAOD/CMakeLists.txt
index 7da1f2db709e3593c00a6bbfb82c15aad4d51ace..8322c4c145169f35b3dccb565b8173ab0fb13329 100644
--- a/Trigger/TrigConfiguration/TrigConfxAOD/CMakeLists.txt
+++ b/Trigger/TrigConfiguration/TrigConfxAOD/CMakeLists.txt
@@ -20,6 +20,7 @@ atlas_depends_on_subdirs(
    PUBLIC
    Control/AthToolSupport/AsgTools
    Event/xAOD/xAODTrigger
+   Trigger/TrigConfiguration/TrigConfData
    Trigger/TrigConfiguration/TrigConfHLTData
    Trigger/TrigConfiguration/TrigConfInterfaces
    Trigger/TrigConfiguration/TrigConfL1Data
@@ -33,13 +34,13 @@ find_package( ROOT COMPONENTS Core RIO )
 atlas_add_library( TrigConfxAODLib
    TrigConfxAOD/*.h Root/*.cxx
    PUBLIC_HEADERS TrigConfxAOD
-   LINK_LIBRARIES AsgTools xAODTrigger TrigConfL1Data TrigConfHLTData
+   LINK_LIBRARIES AsgTools xAODTrigger TrigConfL1Data TrigConfHLTData TrigConfData
    TrigConfInterfaces )
 
 if( NOT XAOD_STANDALONE )
    atlas_add_component( TrigConfxAOD
       src/*.h src/*.cxx src/components/*.cxx
-      LINK_LIBRARIES AthenaBaseComps AthenaKernel StoreGateLib GaudiKernel
+      LINK_LIBRARIES AthenaBaseComps AthenaKernel StoreGateLib GaudiKernel TrigConfData
       TrigConfxAODLib )
 endif()
 
diff --git a/Trigger/TrigConfiguration/TrigConfxAOD/Root/prepareTriggerMenu.cxx b/Trigger/TrigConfiguration/TrigConfxAOD/Root/prepareTriggerMenu.cxx
index 72b17e29dc6259cd4f2b415ecb4cd80a12af2870..fc8d52c37c6b996b4ca522937871194c45500af9 100644
--- a/Trigger/TrigConfiguration/TrigConfxAOD/Root/prepareTriggerMenu.cxx
+++ b/Trigger/TrigConfiguration/TrigConfxAOD/Root/prepareTriggerMenu.cxx
@@ -65,6 +65,10 @@ namespace TrigConf {
             ctpConfig.prescaleSet().setPrescale( menu->itemCtpIds()[ i ],
 						 static_cast< float >( menu->itemPrescales()[ i ] ) );
          }
+         if( msg.level() <= MSG::VERBOSE ) {
+            msg << MSG::VERBOSE << "L1 item " << menu->itemNames()[ i ]
+                << " has ctpid " << menu->itemCtpIds()[ i ] << endmsg;
+         }
       }
 
       // Clear the current HLT configuration:
@@ -115,8 +119,9 @@ namespace TrigConf {
              */
 
             if( msg.level() <= MSG::VERBOSE ) {
-               msg << MSG::VERBOSE << "chain has " << counters.size()
-                   << " signatures" << endmsg;
+               msg << MSG::VERBOSE << "chain " << menu->chainNames()[ i ]
+                   << " has counter " << menu->chainIds()[ i ]
+                   << " and " << counters.size() << " signatures" << endmsg;
             }
             for( size_t sig = 0; sig < counters.size(); ++sig ) {
                std::vector< HLTTriggerElement* > outTEs;
diff --git a/Trigger/TrigConfiguration/TrigConfxAOD/src/PrintVectorHelper.h b/Trigger/TrigConfiguration/TrigConfxAOD/src/PrintVectorHelper.h
new file mode 100644
index 0000000000000000000000000000000000000000..d8724c6b4fa532fa8819f918b26e2396331a0b86
--- /dev/null
+++ b/Trigger/TrigConfiguration/TrigConfxAOD/src/PrintVectorHelper.h
@@ -0,0 +1,30 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef TRIGCONFXAOD_PRINTVECTORHELPER_H
+#define TRIGCONFXAOD_PRINTVECTORHELPER_H
+
+namespace {
+   /// Helper operator for printing the contents of vectors
+   template< typename T >
+   MsgStream& operator<< ( MsgStream& out,
+                           const std::vector< T >& vec ) {
+
+      // A little prefix:
+      out << "[";
+      // Print the contents:
+      for( size_t i = 0; i < vec.size(); ++i ) {
+         out << vec[ i ];
+         if( i < vec.size() - 1 ) {
+            out << ", ";
+         }
+      }
+      // A little postfix:
+      out << "]";
+      // Return the stream:
+      return out;
+   }
+}
+
+#endif
diff --git a/Trigger/TrigConfiguration/TrigConfxAOD/src/components/TrigConfxAOD_entries.cxx b/Trigger/TrigConfiguration/TrigConfxAOD/src/components/TrigConfxAOD_entries.cxx
index d9cbad1f72d87f705cd1e948673155497f81fd79..f4c2ec1c3c4511654d0a1b38c318135a09870362 100644
--- a/Trigger/TrigConfiguration/TrigConfxAOD/src/components/TrigConfxAOD_entries.cxx
+++ b/Trigger/TrigConfiguration/TrigConfxAOD/src/components/TrigConfxAOD_entries.cxx
@@ -1,10 +1,12 @@
 #include "../xAODConfigSvc.h"
 #include "../xAODMenuWriter.h"
+#include "../xAODMenuWriterMT.h"
 #include "../xAODMenuReader.h"
 #include "TrigConfxAOD/xAODConfigTool.h"
 
 DECLARE_COMPONENT( TrigConf::xAODConfigSvc )
 DECLARE_COMPONENT( TrigConf::xAODMenuWriter )
+DECLARE_COMPONENT( TrigConf::xAODMenuWriterMT )
 DECLARE_COMPONENT( TrigConf::xAODMenuReader )
 DECLARE_COMPONENT( TrigConf::xAODConfigTool )
 
diff --git a/Trigger/TrigConfiguration/TrigConfxAOD/src/xAODMenuWriter.cxx b/Trigger/TrigConfiguration/TrigConfxAOD/src/xAODMenuWriter.cxx
index 9ed53ffef6351be1e2267b454a885a72686e3993..5ac47c5e7e85dbdcd894f182a48f4e59552ba036 100644
--- a/Trigger/TrigConfiguration/TrigConfxAOD/src/xAODMenuWriter.cxx
+++ b/Trigger/TrigConfiguration/TrigConfxAOD/src/xAODMenuWriter.cxx
@@ -27,28 +27,7 @@
 
 // Local include(s):
 #include "xAODMenuWriter.h"
-
-namespace {
-   /// Helper operator for printing the contents of vectors
-   template< typename T >
-   MsgStream& operator<< ( MsgStream& out,
-                           const std::vector< T >& vec ) {
-
-      // A little prefix:
-      out << "[";
-      // Print the contents:
-      for( size_t i = 0; i < vec.size(); ++i ) {
-         out << vec[ i ];
-         if( i < vec.size() - 1 ) {
-            out << ", ";
-         }
-      }
-      // A little postfix:
-      out << "]";
-      // Return the stream:
-      return out;
-   }
-}
+#include "PrintVectorHelper.h"
 
 namespace TrigConf {
 
diff --git a/Trigger/TrigConfiguration/TrigConfxAOD/src/xAODMenuWriterMT.cxx b/Trigger/TrigConfiguration/TrigConfxAOD/src/xAODMenuWriterMT.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..3091cfdb74fe699c1fe97c830ec0ce45bc156fee
--- /dev/null
+++ b/Trigger/TrigConfiguration/TrigConfxAOD/src/xAODMenuWriterMT.cxx
@@ -0,0 +1,413 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+// Gaudi/Athena include(s):
+#include "AthenaKernel/errorcheck.h"
+
+// Trigger configuration include(s):
+#include "TrigConfL1Data/CTPConfig.h"
+#include "TrigConfL1Data/Menu.h"
+#include "TrigConfL1Data/TriggerItem.h"
+#include "TrigConfL1Data/PrescaleSet.h"
+#include "TrigConfL1Data/BunchGroupSet.h"
+#include "TrigConfL1Data/BunchGroup.h"
+#include "TrigConfHLTData/HLTChainList.h"
+#include "TrigConfHLTData/HLTChain.h"
+#include "TrigConfHLTData/HLTSignature.h"
+#include "TrigConfHLTData/HLTTriggerElement.h"
+#include "TrigConfHLTData/HLTSequenceList.h"
+
+// EDM include(s):
+#include "xAODTrigger/TriggerMenu.h"
+#include "xAODTrigger/TriggerMenuAuxContainer.h"
+
+// Local include(s):
+#include "xAODMenuWriterMT.h"
+#include "PrintVectorHelper.h"
+
+
+namespace TrigConf {
+
+   xAODMenuWriterMT::xAODMenuWriterMT( const std::string& name,
+                                       ISvcLocator* svcLoc )
+      : AthReentrantAlgorithm( name, svcLoc ),
+        m_trigConf( "TrigConfigSvc", name ),
+        m_metaStore( "MetaDataStore", name ),
+        m_tmc( nullptr ) {
+   }
+
+   xAODMenuWriterMT::~xAODMenuWriterMT() {
+   }
+
+   StatusCode xAODMenuWriterMT::initialize() {
+
+      // Greet the user:
+      ATH_MSG_INFO( "Initialising - Package version: " << PACKAGE_VERSION );
+      ATH_MSG_DEBUG( "EventObjectName   = " << m_eventName );
+      ATH_MSG_DEBUG( "MetaObjectName    = " << m_metaName );
+      ATH_MSG_VERBOSE( "TrigConfigSvc = " << m_trigConf );
+      ATH_MSG_VERBOSE( "MetaDataStore = " << m_metaStore );
+
+      // Retrieve the necessary service(s):
+      CHECK( m_trigConf.retrieve() );
+      CHECK( m_metaStore.retrieve() );
+
+      CHECK( m_eventName.initialize() ); // WriteHandleKey
+
+      if (m_isJSONConfig) {
+         CHECK( m_HLTMenuKey.initialize() ); // ReadHandleKey
+         CHECK( m_L1MenuKey.initialize() ); // ReadHandleKey
+      }
+
+      // Clear the internal cache variable:
+      m_convertedKeys.clear();
+
+      // Create an empty trigger menu container:
+      xAOD::TriggerMenuAuxContainer* aux = new xAOD::TriggerMenuAuxContainer();
+      m_tmc = new xAOD::TriggerMenuContainer();
+      m_tmc->setStore( aux );
+
+      // Record the trigger configuration metadata into it:
+      CHECK( m_metaStore->record( aux, m_metaName + "Aux." ) );
+      CHECK( m_metaStore->record( m_tmc, m_metaName ) );
+
+      // Return gracefully:
+      return StatusCode::SUCCESS;
+   }
+
+   StatusCode xAODMenuWriterMT::execute(const EventContext& ctx) const {
+
+      std::unique_ptr<xAOD::TrigConfKeys> keys = std::make_unique<xAOD::TrigConfKeys>(
+         m_trigConf->masterKey(),
+         m_trigConf->lvl1PrescaleKey(),
+         m_trigConf->hltPrescaleKey() );
+
+      SG::WriteHandle<xAOD::TrigConfKeys> trigConfKeysWrite(m_eventName, ctx);
+      ATH_CHECK( trigConfKeysWrite.record( std::move(keys) ) );
+
+      // Create the keys in the "internal format":
+      const TrigKey_t ckeys =
+         std::make_pair( m_trigConf->masterKey(),
+                         std::make_pair( m_trigConf->lvl1PrescaleKey(),
+                                         m_trigConf->hltPrescaleKey() ) );
+
+      // The followign code must only run on one event at a time
+      std::lock_guard<std::mutex> lock(m_mutex);
+
+      // Check if we converted this configuration already:
+      if( ! m_convertedKeys.insert( ckeys ).second ) {
+         ATH_MSG_VERBOSE( "Configuration with keys SMK: "
+                          << ckeys.first << ", L1PSK: " << ckeys.second.first
+                          << ", HLTPSK: " << ckeys.second.second
+                          << " already translated" );
+         return StatusCode::SUCCESS;
+      }
+
+      // Tell the user what's happening:
+      ATH_MSG_INFO( "Converting configuration with keys SMK: "
+                    << ckeys.first << ", L1PSK: " << ckeys.second.first
+                    << ", HLTPSK: " << ckeys.second.second );
+
+      // Apparently not, so let's make a new object:
+      xAOD::TriggerMenu* menu = new xAOD::TriggerMenu();
+      m_tmc->push_back( menu ); // Now owned by MetaDataStore
+
+      //
+      // Set its keys:
+      //
+      menu->setSMK( m_trigConf->masterKey() );
+      menu->setL1psk( m_trigConf->lvl1PrescaleKey() );
+      menu->setHLTpsk( m_trigConf->hltPrescaleKey() );
+
+      if (m_isJSONConfig) {
+         CHECK( populateFromJSON(menu, ctx) );
+      } else {
+         CHECK( populateFromTrigConf(menu) );
+      }
+
+      CHECK( populateBunchGroup(menu) ); 
+
+      // Return gracefully:
+      return StatusCode::SUCCESS;
+   }
+
+   StatusCode xAODMenuWriterMT::populateFromJSON(xAOD::TriggerMenu* menu, const EventContext& ctx) const {
+      //
+      // Set its LVL1 information:
+      //
+      ATH_MSG_DEBUG( "Filling LVL1 information" );
+      SG::ReadHandle<TrigConf::L1Menu> l1MenuHandle = SG::makeHandle( m_L1MenuKey, ctx );
+      ATH_CHECK( l1MenuHandle.isValid() );
+      const size_t nL1Items = l1MenuHandle->size();
+      ATH_MSG_DEBUG("Configuring from " << m_L1MenuKey << " with " << nL1Items << " L1 items");
+
+      std::vector< uint16_t > ctpIds;
+      std::vector< std::string > itemNames;
+      std::vector< float > itemPrescales;
+
+      ctpIds.reserve(nL1Items);
+      itemNames.reserve(nL1Items);
+      itemPrescales.reserve(nL1Items);
+
+      for (const TrigConf::L1Item& l1 : *l1MenuHandle) {
+         // Extract the information:
+         ctpIds.push_back( l1.ctpId() );
+         itemNames.push_back( l1.name() );
+         itemPrescales.push_back( 1.0 ); // TODO
+
+         // Some verbose information:
+         ATH_MSG_VERBOSE( "  \"" << itemNames.back() << "\" CTP Id = "
+                          << ctpIds.back() << ", prescale = "
+                          << itemPrescales.back() );
+      }
+
+      menu->setItemCtpIds( ctpIds );
+      menu->setItemNames( itemNames );
+      menu->setItemPrescales( itemPrescales );
+
+      //
+      // Set its HLT information:
+      //
+      ATH_MSG_DEBUG( "Filling HLT information" );
+      SG::ReadHandle<TrigConf::HLTMenu> hltMenuHandle = SG::makeHandle( m_HLTMenuKey, ctx );
+      ATH_CHECK( hltMenuHandle.isValid() );
+      const size_t nChains = hltMenuHandle->size();
+      ATH_MSG_DEBUG("Configuring from " << m_HLTMenuKey << " with " << nChains << " chains");
+
+      std::vector< uint16_t > chainIds;
+      std::vector< std::string > chainNames, chainParentNames;
+      std::vector< float > chainPrescales, chainRerunPrescales,
+         chainPassthroughPrescales;
+
+      std::vector< std::vector< uint32_t > > chainSignatureCounters;
+      std::vector< std::vector< int > > chainSignatureLogics;
+      std::vector< std::vector< std::vector< std::string > > > chainSignatureOutputTEs;
+      std::vector< std::vector< std::string > > chainSignatureLabels;
+
+      chainIds.reserve(nChains);
+      chainNames.reserve(nChains);
+      chainParentNames.reserve(nChains);
+      chainPrescales.reserve(nChains);
+      chainRerunPrescales.reserve(nChains);
+      chainPassthroughPrescales.reserve(nChains);
+
+      chainSignatureCounters.reserve(nChains);
+      chainSignatureLogics.reserve(nChains);
+      chainSignatureOutputTEs.reserve(nChains);
+      chainSignatureLabels.reserve(nChains);
+
+      for (const TrigConf::Chain& ch : *hltMenuHandle) {
+         // Extract the information:
+         chainIds.push_back( ch.counter() );
+         chainNames.push_back( ch.name() );
+         chainParentNames.push_back( ch.l1item() );
+         chainPrescales.push_back( 1.0 ); // TODO
+         chainRerunPrescales.push_back( -1.0 ); // TODO
+         chainPassthroughPrescales.push_back( 0.0 ); // Unused in Run3
+
+         std::vector<uint32_t> counters;
+         std::vector<int> logics;
+         std::vector<std::vector<std::string> > outputTEs;
+         std::vector<std::string> labels;
+
+         // Per-step algorithms is TODO, these are blank for now.
+
+         chainSignatureCounters.push_back(counters);
+         chainSignatureLogics.push_back(logics);
+         chainSignatureOutputTEs.push_back(outputTEs);
+         chainSignatureLabels.push_back(labels);
+
+         // Some verbose information:
+         ATH_MSG_VERBOSE( "  \"" << chainNames.back() << "\" Chain Id = "
+                          << chainIds.back() << ", parent name = \""
+                          << chainParentNames.back() << "\", prescale = "
+                          << chainPrescales.back() << ", re-run prescale = "
+                          << chainRerunPrescales.back()
+                          << ", pass-through presclale = "
+                          << chainPassthroughPrescales.back() );
+      }
+
+      menu->setChainIds( chainIds );
+      menu->setChainNames( chainNames );
+      menu->setChainParentNames( chainParentNames );
+      menu->setChainPrescales( chainPrescales );
+      menu->setChainRerunPrescales( chainRerunPrescales );
+      menu->setChainPassthroughPrescales( chainPassthroughPrescales );
+
+      menu->setChainSignatureCounters(chainSignatureCounters);
+      menu->setChainSignatureLogics(chainSignatureLogics);
+      menu->setChainSignatureOutputTEs(chainSignatureOutputTEs);
+      menu->setChainSignatureLabels(chainSignatureLabels);
+
+      //
+      // Set its sequence information:
+      //
+      // TODO
+
+      return StatusCode::SUCCESS;
+   }
+
+
+   StatusCode xAODMenuWriterMT::populateFromTrigConf(xAOD::TriggerMenu* menu) const {
+      //
+      // Set its LVL1 information:
+      //
+      ATH_MSG_DEBUG( "Filling LVL1 information" );
+      std::vector< uint16_t > ctpIds;
+      std::vector< std::string > itemNames;
+      std::vector< float > itemPrescales;
+      TrigConf::ItemContainer::const_iterator item_itr =
+         m_trigConf->ctpConfig()->menu().items().begin();
+      TrigConf::ItemContainer::const_iterator item_end =
+         m_trigConf->ctpConfig()->menu().items().end();
+      std::vector< float > prescales =
+         m_trigConf->ctpConfig()->prescaleSet().prescales_float();
+      for( ; item_itr != item_end; ++item_itr ) {
+
+         // Extract the information:
+         ctpIds.push_back( ( *item_itr )->ctpId() );
+         itemNames.push_back( ( *item_itr )->name() );
+         itemPrescales.push_back( prescales[ ( *item_itr )->ctpId() ] );
+
+         // Some verbose information:
+         ATH_MSG_VERBOSE( "  \"" << itemNames.back() << "\" CTP Id = "
+                          << ctpIds.back() << ", prescale = "
+                          << itemPrescales.back() );
+      }
+      menu->setItemCtpIds( ctpIds );
+      menu->setItemNames( itemNames );
+      menu->setItemPrescales( itemPrescales );
+
+      //
+      // Set its HLT information:
+      //
+      ATH_MSG_DEBUG( "Filling HLT information" );
+      std::vector< uint16_t > chainIds;
+      std::vector< std::string > chainNames, chainParentNames;
+      std::vector< float > chainPrescales, chainRerunPrescales,
+         chainPassthroughPrescales;
+
+      std::vector< std::vector< uint32_t > > chainSignatureCounters;
+      std::vector< std::vector< int > > chainSignatureLogics;
+      std::vector< std::vector< std::vector< std::string > > > chainSignatureOutputTEs;
+      std::vector< std::vector< std::string > > chainSignatureLabels;
+
+      TrigConf::HLTChainList::const_iterator chain_itr =
+         m_trigConf->chains().begin();
+      TrigConf::HLTChainList::const_iterator chain_end =
+         m_trigConf->chains().end();
+      for( ; chain_itr != chain_end; ++chain_itr ) {
+
+         // Extract the information:
+         chainIds.push_back( ( *chain_itr )->chain_counter() );
+         chainNames.push_back( ( *chain_itr )->chain_name() );
+         chainParentNames.push_back( ( *chain_itr )->lower_chain_name() );
+         chainPrescales.push_back( ( *chain_itr )->prescale() );
+         chainRerunPrescales.push_back(
+                                       ( *chain_itr )->prescales().getRerunPrescale("").second );
+         chainPassthroughPrescales.push_back( ( *chain_itr )->pass_through() );
+
+         std::vector<uint32_t> counters;
+         std::vector<int> logics;
+         std::vector<std::vector<std::string> > outputTEs;
+         std::vector<std::string> labels;
+
+         ATH_MSG_VERBOSE((*chain_itr)->chain_name() << " has " << (*chain_itr)->signatureList().size() << " signatures");
+         for(auto& signature : (*chain_itr)->signatureList() ){
+            uint32_t cntr = signature->signature_counter();
+            counters.push_back(cntr);
+            logics.push_back(signature->logic());
+            labels.push_back(signature->label());
+            std::vector<std::string> outputTEids;
+            for(auto& outputTE : signature->outputTEs()){
+               outputTEids.push_back(outputTE->name());
+            }
+            outputTEs.push_back(outputTEids);
+            ATH_MSG_VERBOSE("converted this signature: " << *signature);
+         }
+         chainSignatureCounters.push_back(counters);
+         chainSignatureLogics.push_back(logics);
+         chainSignatureOutputTEs.push_back(outputTEs);
+         chainSignatureLabels.push_back(labels);
+
+         // Some verbose information:
+         ATH_MSG_VERBOSE( "  \"" << chainNames.back() << "\" Chain Id = "
+                          << chainIds.back() << ", parent name = \""
+                          << chainParentNames.back() << "\", prescale = "
+                          << chainPrescales.back() << ", re-run prescale = "
+                          << chainRerunPrescales.back()
+                          << ", pass-through presclale = "
+                          << chainPassthroughPrescales.back() );
+      }
+      menu->setChainIds( chainIds );
+      menu->setChainNames( chainNames );
+      menu->setChainParentNames( chainParentNames );
+      menu->setChainPrescales( chainPrescales );
+      menu->setChainRerunPrescales( chainRerunPrescales );
+      menu->setChainPassthroughPrescales( chainPassthroughPrescales );
+
+      menu->setChainSignatureCounters(chainSignatureCounters);
+      menu->setChainSignatureLogics(chainSignatureLogics);
+      menu->setChainSignatureOutputTEs(chainSignatureOutputTEs);
+      menu->setChainSignatureLabels(chainSignatureLabels);
+
+      //
+      // Set its sequence information:
+      //
+      ATH_MSG_DEBUG( "Filling sequence information" );
+      auto& sequenceList = m_trigConf->sequences();
+      std::vector<std::vector<std::string> > sequenceInputTEs;
+      std::vector<std::string> sequenceOutputTE;
+      std::vector<std::vector<std::string> > sequenceAlgorithms;
+
+      for(auto& seq : sequenceList){
+         std::vector<std::string> inputTEs;
+         for(auto& input : seq->inputTEs()) inputTEs.push_back(input->name());
+         sequenceInputTEs.push_back(inputTEs);
+         sequenceAlgorithms.push_back(seq->algorithms());
+         sequenceOutputTE.push_back(seq->outputTE()->name());
+
+         ATH_MSG_VERBOSE("original sequence: \n" << *seq);
+
+         ATH_MSG_VERBOSE("added sequence with: ");
+         ATH_MSG_VERBOSE("  inputTEs: " << sequenceInputTEs.back());
+         ATH_MSG_VERBOSE("     algos: " << sequenceAlgorithms.back());
+         ATH_MSG_VERBOSE("  outputTE: " << sequenceOutputTE.back());
+      }
+
+      menu->setSequenceInputTEs(sequenceInputTEs);
+      menu->setSequenceOutputTEs(sequenceOutputTE);
+      menu->setSequenceAlgorithms(sequenceAlgorithms);
+
+      return StatusCode::SUCCESS;
+   }
+
+   StatusCode xAODMenuWriterMT::populateBunchGroup(xAOD::TriggerMenu* menu) const {
+      //
+      // Set its bunch-group information:
+      //
+      ATH_MSG_DEBUG( "Filling bunch-group information" );
+      std::vector< std::vector< uint16_t > > bgs;
+      std::vector< BunchGroup >::const_iterator bg_itr =
+         m_trigConf->bunchGroupSet()->bunchGroups().begin();
+      std::vector< BunchGroup >::const_iterator bg_end =
+         m_trigConf->bunchGroupSet()->bunchGroups().end();
+      for( int i = 0; bg_itr != bg_end; ++bg_itr, ++i ) {
+
+         // Extract the information. Unfortunately we need to make
+         // and explicit conversion by hand.
+         const std::vector< uint16_t > bunches( bg_itr->bunches().begin(),
+                                                bg_itr->bunches().end() );
+         bgs.push_back( bunches );
+
+         // Some verbose information:
+         ATH_MSG_VERBOSE( "  Bunch group " << i << " bunches: "
+                          << bgs.back() );
+      }
+      menu->setBunchGroupBunches( bgs );
+
+      return StatusCode::SUCCESS;
+   }
+
+} // namespace TrigConf
diff --git a/Trigger/TrigConfiguration/TrigConfxAOD/src/xAODMenuWriterMT.h b/Trigger/TrigConfiguration/TrigConfxAOD/src/xAODMenuWriterMT.h
new file mode 100644
index 0000000000000000000000000000000000000000..ede39616dc848535455cb6569216f93b40afac8e
--- /dev/null
+++ b/Trigger/TrigConfiguration/TrigConfxAOD/src/xAODMenuWriterMT.h
@@ -0,0 +1,109 @@
+// Dear emacs, this is -*- c++ -*-
+
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef TRIGCONFXAOD_XAODMENUWRITERMT_H
+#define TRIGCONFXAOD_XAODMENUWRITERMT_H
+
+// System include(s):
+extern "C" {
+#   include <stdint.h>
+}
+#include <string>
+#include <set>
+#include <map> // For std::pair...
+
+// Gaudi/Athena include(s):
+#include "AthenaBaseComps/AthReentrantAlgorithm.h"
+#include "GaudiKernel/ServiceHandle.h"
+#include "StoreGate/StoreGateSvc.h"
+
+// Trigger include(s):
+#include "TrigConfInterfaces/ITrigConfigSvc.h"
+#include "TrigConfData/HLTMenu.h"
+#include "TrigConfData/L1Menu.h"
+
+// EDM include(s):
+#include "xAODTrigger/TriggerMenuContainer.h"
+#include "xAODTrigger/TrigConfKeys.h"
+
+namespace TrigConf {
+
+   /**
+    *  @short Algorithm used to write the light-weight xAOD configuration
+    *
+    *         This algorithm needs to be scheduled in jobs that write xAOD
+    *         files in Athena in order to write the trigger configuration
+    *         into the output file.
+    *
+    *         It puts a tiny amount of information into each event that is
+    *         later used to find the correct configuration of the events,
+    *         and also assembles the configuration metadata that is written
+    *         into the metadata TTree of the xAOD file at the end of the job.
+    *
+    * @author Attila Krasznahorkay <Attila.Krasznahorkay@cern.ch>
+    * @author Tim Martin <Tim.Martin@cern.ch>
+    *
+    */
+   class xAODMenuWriterMT : public AthReentrantAlgorithm {
+
+   public:
+      /// Regular Algorithm constructor
+      xAODMenuWriterMT( const std::string& name, ISvcLocator* svcLoc );
+
+      virtual ~xAODMenuWriterMT();
+
+      /// Function initialising the algorithm
+      virtual StatusCode initialize() override;
+
+      /// Function executing the algorithm
+      virtual StatusCode execute(const EventContext& ctx) const override;
+
+   private:
+      /// 
+      SG::WriteHandleKey<xAOD::TrigConfKeys> m_eventName {this, "EventObjectName", "TrigConfKeys",
+        "StoreGate key for the event object"};
+
+       SG::ReadHandleKey<TrigConf::HLTMenu> m_HLTMenuKey {this, "HLTTriggerMenu", "DetectorStore+HLTTriggerMenu",
+        "HLT Menu key, for use if IsJSONConfig=True"};
+
+       SG::ReadHandleKey<TrigConf::L1Menu> m_L1MenuKey {this, "L1TriggerMenu", "DetectorStore+L1TriggerMenu",
+        "L1 Menu key, for use if IsJSONConfig=True"};
+
+      Gaudi::Property< std::string > m_metaName {this, "MetaObjectName", "TriggerMenu",
+        "StoreGate key for the configuration object"};
+
+      Gaudi::Property< bool > m_isJSONConfig {this, "IsJSONConfig", true,
+        "If converting from a JSON menu (Run3) or from the TrigConfigSvc (Runs 1, 2)"};
+
+      ServiceHandle< TrigConf::ITrigConfigSvc > m_trigConf {this, "TrigConfigSvc", "TrigConfigSvc",
+        "The TrigConfigSvc"};
+
+      ServiceHandle< StoreGateSvc > m_metaStore {this, "MetaDataStore", "MetaDataStore",
+        "The MetaDataStore"};
+
+      StatusCode populateFromTrigConf(xAOD::TriggerMenu* menu) const;
+
+      StatusCode populateFromJSON(xAOD::TriggerMenu* menu, const EventContext& ctx) const;
+
+      StatusCode populateBunchGroup(xAOD::TriggerMenu* menu) const;
+
+      /// Trigger configuration key type (used just internally)
+      typedef std::pair< uint32_t, std::pair< uint32_t, uint32_t > > TrigKey_t;
+
+      /// The configuration object that we are writing
+      mutable xAOD::TriggerMenuContainer* m_tmc;
+
+      /// Trigger configuration keys that are already converted
+      mutable std::set< TrigKey_t > m_convertedKeys;
+
+      /// The mutex to prevent us from writing more than one configuration at a time
+      mutable std::mutex m_mutex;
+
+   }; // class xAODMenuWriterMT
+
+} // namespace TrigConf
+
+#endif // TRIGCONFXAOD_XAODMENUWRITERMT_H
diff --git a/Trigger/TrigEvent/TrigSteeringEvent/TrigSteeringEvent/HLTResultMT.h b/Trigger/TrigEvent/TrigSteeringEvent/TrigSteeringEvent/HLTResultMT.h
index 64208fd5d22ceafc7a3ad45c38fa8d9633d6f874..040a0c90228786382c8be4bbe46d71b4c7895452 100644
--- a/Trigger/TrigEvent/TrigSteeringEvent/TrigSteeringEvent/HLTResultMT.h
+++ b/Trigger/TrigEvent/TrigSteeringEvent/TrigSteeringEvent/HLTResultMT.h
@@ -34,7 +34,9 @@ namespace HLT {
   public:
     /// Standard constructor
     HLTResultMT(std::vector<eformat::helper::StreamTag> streamTags = {},
-                boost::dynamic_bitset<uint32_t> hltBits = boost::dynamic_bitset<uint32_t>(),
+                boost::dynamic_bitset<uint32_t> hltPassRawBits = boost::dynamic_bitset<uint32_t>(),
+                boost::dynamic_bitset<uint32_t> hltPrescaledBits = boost::dynamic_bitset<uint32_t>(),
+                boost::dynamic_bitset<uint32_t> hltRerunBits = boost::dynamic_bitset<uint32_t>(),
                 std::unordered_map<uint16_t, std::vector<uint32_t> > data = {},
                 std::vector<uint32_t> status = {0});
 
@@ -64,26 +66,27 @@ namespace HLT {
 
     // ------------------------- HLT bits getters/setters ----------------------
 
-    /// Const-getter for HLT bits
-    const boost::dynamic_bitset<uint32_t>& getHltBits() const;
+    /// Const-getter for HLT pass raw bits
+    const boost::dynamic_bitset<uint32_t>& getHltPassRawBits() const;
 
-    /// Const-getter for HLT bits as uint32_t array
-    const std::vector<uint32_t>& getHltBitsAsWords();
+    /// Const-getter for HLT prescaled bits
+    const boost::dynamic_bitset<uint32_t>& getHltPrescaledBits() const;
 
-    /// Replace HLT bits with the given bitset
-    void setHltBits(const boost::dynamic_bitset<uint32_t>& bitset);
+    /// Const-getter for HLT rerun bits
+    const boost::dynamic_bitset<uint32_t>& getHltRerunBits() const;
 
-    /** @brief Sets bit at the given index to true
-     *  @return FAILURE on memory allocation error
-     **/
-    StatusCode addHltBit(size_t index);
+    /// Const-getter for HLT bits as uint32_t array. Ordering: PassRaw, Prescaled, Rerun.
+    const std::vector<uint32_t>& getHltBitsAsWords();
 
-    /** @brief Sets bits at the given indices to true
-     *  @return FAILURE on memory allocation error
-     **/
-    StatusCode addHltBits(const std::vector<size_t>& indices);
+    /// Replace HLT pass raw bits with the given bitset
+    void setHltPassRawBits(const boost::dynamic_bitset<uint32_t>& bitset);
 
+    /// Replace HLT prescaled bits with the given bitset
+    void setHltPrescaledBits(const boost::dynamic_bitset<uint32_t>& bitset);
 
+    /// Replace HLT rerun raw bits with the given bitset
+    void setHltRerunBits(const boost::dynamic_bitset<uint32_t>& bitset);
+    
     // ------------------------- Serialised data getters/setters ---------------
 
     /** @brief Serialised data getter
@@ -152,12 +155,14 @@ namespace HLT {
     std::vector<eformat::helper::StreamTag> m_streamTags;
 
     /// HLT bits (flagging which chains passed)
-    boost::dynamic_bitset<uint32_t> m_hltBits;
+    boost::dynamic_bitset<uint32_t> m_hltPassRawBits;
+    boost::dynamic_bitset<uint32_t> m_hltPrescaledBits;
+    boost::dynamic_bitset<uint32_t> m_hltRerunBits;
 
     /** @brief Vector storing m_hltBits converted to 4-byte words
      *
      *  HLTResultMT needs to own this vector because its lifetime has to be ensured until the serialisation is finished.
-     *  This vector is updated internally from m_hltBits and does not have a setter method.
+     *  This vector is updated internally from m_hltPassRawBits, m_hltPrescaledBits, m_hltRerunBits and does not have a setter method.
      **/
     std::vector<uint32_t> m_hltBitWords;
 
diff --git a/Trigger/TrigEvent/TrigSteeringEvent/src/HLTResultMT.cxx b/Trigger/TrigEvent/TrigSteeringEvent/src/HLTResultMT.cxx
index 873d3a2db6df17c28e35127a1790bcc9f87d0310..c0806edfb79b1e6276c381cc26237cd23e86a44b 100644
--- a/Trigger/TrigEvent/TrigSteeringEvent/src/HLTResultMT.cxx
+++ b/Trigger/TrigEvent/TrigSteeringEvent/src/HLTResultMT.cxx
@@ -12,11 +12,15 @@
 // Standard constructor
 // =============================================================================
 HLT::HLTResultMT::HLTResultMT(std::vector<eformat::helper::StreamTag> streamTags,
-                              boost::dynamic_bitset<uint32_t> hltBits,
+                              boost::dynamic_bitset<uint32_t> hltPassRawBits,
+                              boost::dynamic_bitset<uint32_t> hltPrescaledBits,
+                              boost::dynamic_bitset<uint32_t> hltRerunBits,
                               std::unordered_map<uint16_t, std::vector<uint32_t> > data,
                               std::vector<uint32_t> status)
 : m_streamTags(streamTags),
-  m_hltBits(hltBits),
+  m_hltPassRawBits(hltPassRawBits),
+  m_hltPrescaledBits(hltPrescaledBits),
+  m_hltRerunBits(hltRerunBits),
   m_data(data),
   m_status(status) {}
 
@@ -70,49 +74,49 @@ StatusCode HLT::HLTResultMT::addStreamTag(const eformat::helper::StreamTag& stre
 // =============================================================================
 // Getter/setter methods for trigger bits
 // =============================================================================
-const boost::dynamic_bitset<uint32_t>& HLT::HLTResultMT::getHltBits() const {
-  return m_hltBits;
+const boost::dynamic_bitset<uint32_t>& HLT::HLTResultMT::getHltPassRawBits() const {
+  return m_hltPassRawBits;
+}
+
+// -----------------------------------------------------------------------------
+const boost::dynamic_bitset<uint32_t>& HLT::HLTResultMT::getHltPrescaledBits() const {
+  return m_hltPrescaledBits;
+}
+
+// -----------------------------------------------------------------------------
+const boost::dynamic_bitset<uint32_t>& HLT::HLTResultMT::getHltRerunBits() const {
+  return m_hltRerunBits;
 }
 
 // -----------------------------------------------------------------------------
 const std::vector<uint32_t>& HLT::HLTResultMT::getHltBitsAsWords() {
   m_hltBitWords.clear();
-  m_hltBitWords.resize(m_hltBits.num_blocks());
-  boost::to_block_range(m_hltBits,m_hltBitWords.begin());
+  if (m_hltPassRawBits.num_blocks() != m_hltPrescaledBits.num_blocks() || m_hltPassRawBits.num_blocks() != m_hltRerunBits.num_blocks()) {
+    throw std::runtime_error("Must have the same number of bits in m_hltPassRawBits, m_hltPrescaledBits and m_hltRerunBits.");
+  }
+  m_hltBitWords.resize(m_hltPassRawBits.num_blocks() + m_hltPrescaledBits.num_blocks() + m_hltRerunBits.num_blocks());
+  boost::to_block_range(m_hltPassRawBits, m_hltBitWords.begin());
+  boost::to_block_range(m_hltPrescaledBits, m_hltBitWords.begin() + m_hltPassRawBits.num_blocks());
+  boost::to_block_range(m_hltRerunBits, m_hltBitWords.begin() + m_hltPassRawBits.num_blocks() + m_hltPrescaledBits.num_blocks());
   return m_hltBitWords;
 }
 
 // -----------------------------------------------------------------------------
-void HLT::HLTResultMT::setHltBits(const boost::dynamic_bitset<uint32_t>& bitset) {
+void HLT::HLTResultMT::setHltPassRawBits(const boost::dynamic_bitset<uint32_t>& bitset) {
   // copy assignment
-  m_hltBits = bitset;
+  m_hltPassRawBits = bitset;
 }
 
 // -----------------------------------------------------------------------------
-StatusCode HLT::HLTResultMT::addHltBit(size_t index) {
-  try {
-    if (m_hltBits.size() <= index) m_hltBits.resize(index+1);
-    m_hltBits.set(index);
-  }
-  catch (const std::exception& ex) {
-    ATH_REPORT_ERROR_WITH_CONTEXT(StatusCode::FAILURE, CONTEXT_NAME)
-      << "Failed to add HLT bit, likely memory allocation failed. std::exception caught: " << ex.what();
-    return StatusCode::FAILURE;
-  }
-  catch (...) {
-    ATH_REPORT_ERROR_WITH_CONTEXT(StatusCode::FAILURE, CONTEXT_NAME)
-      << "Failed to add HLT bit, likely memory allocation failed. Unknown exception caught.";
-    return StatusCode::FAILURE;
-  }
-  return StatusCode::SUCCESS;
+void HLT::HLTResultMT::setHltPrescaledBits(const boost::dynamic_bitset<uint32_t>& bitset) {
+  // copy assignment
+  m_hltPrescaledBits = bitset;
 }
 
 // -----------------------------------------------------------------------------
-StatusCode HLT::HLTResultMT::addHltBits(const std::vector<size_t>& indices) {
-  for (const size_t index : indices) {
-    ATH_CHECK(addHltBit(index));
-  }
-  return StatusCode::SUCCESS;
+void HLT::HLTResultMT::setHltRerunBits(const boost::dynamic_bitset<uint32_t>& bitset) {
+  // copy assignment
+  m_hltRerunBits = bitset;
 }
 
 // =============================================================================
@@ -238,11 +242,23 @@ std::ostream& operator<<(std::ostream& str, const HLT::HLTResultMT& hltResult) {
   if (hltResult.getStreamTags().empty()) str << std::endl;
 
   // HLT bits
-  std::vector<uint32_t> hltBitWords;
-  hltBitWords.resize(hltResult.getHltBits().num_blocks());
-  boost::to_block_range(hltResult.getHltBits(),hltBitWords.begin());
+  std::vector<uint32_t> hltPassRawBitWords;
+  std::vector<uint32_t> hltPrescaledBitWords;
+  std::vector<uint32_t> hltRerunBitWords;
+  hltPassRawBitWords.resize(hltResult.getHltPassRawBits().num_blocks());
+  hltPrescaledBitWords.resize(hltResult.getHltPrescaledBits().num_blocks());
+  hltRerunBitWords.resize(hltResult.getHltRerunBits().num_blocks());
+  boost::to_block_range(hltResult.getHltPassRawBits(),hltPassRawBitWords.begin());
+  boost::to_block_range(hltResult.getHltPrescaledBits(),hltPrescaledBitWords.begin());
+  boost::to_block_range(hltResult.getHltRerunBits(),hltRerunBitWords.begin());
   str << "--> HLT bits     = ";
-  for (const uint32_t word : hltBitWords) {
+  for (const uint32_t word : hltPassRawBitWords) {
+    printWord(word);
+  }
+  for (const uint32_t word : hltPrescaledBitWords) {
+    printWord(word);
+  }
+  for (const uint32_t word : hltRerunBitWords) {
     printWord(word);
   }
   str << std::endl;
diff --git a/Trigger/TrigSteer/TrigHLTResultByteStream/src/HLTResultMTByteStreamDecoderTool.cxx b/Trigger/TrigSteer/TrigHLTResultByteStream/src/HLTResultMTByteStreamDecoderTool.cxx
index b87688c463325cbfd76973c2bbc929e5599fcfcf..f78a09207308ba31ba409247b200e41639523a88 100644
--- a/Trigger/TrigSteer/TrigHLTResultByteStream/src/HLTResultMTByteStreamDecoderTool.cxx
+++ b/Trigger/TrigSteer/TrigHLTResultByteStream/src/HLTResultMTByteStreamDecoderTool.cxx
@@ -101,9 +101,19 @@ StatusCode HLTResultMTByteStreamDecoderTool::decodeHeader(const RawEvent* rawEve
     ATH_MSG_ERROR("Unknown exception caught when reading HLT bits");
     return StatusCode::FAILURE;
   }
-  resultToFill.setHltBits( {hltBitWords.begin(), hltBitWords.end()} );
+  if (hltBitWords.size() % 3 != 0) {
+    ATH_MSG_ERROR("Size of hltBitWords=" << hltBitWords.size() << " must be divisible by three. Expecting {raw, prescaled, rerun} bits.");
+    return StatusCode::FAILURE;
+  }
+  const size_t sizeOfBlock = hltBitWords.size() / 3;
+  auto beginPrescaledIt = hltBitWords.begin();
+  std::advance(beginPrescaledIt, sizeOfBlock);
+  auto beginRerunIt = hltBitWords.begin();
+  std::advance(beginRerunIt, 2 * sizeOfBlock);
+  resultToFill.setHltPassRawBits( {hltBitWords.begin(), beginPrescaledIt} );
+  resultToFill.setHltPrescaledBits( {beginPrescaledIt, beginRerunIt} );
+  resultToFill.setHltRerunBits( {beginRerunIt, hltBitWords.end()} );
   ATH_MSG_DEBUG("Successfully read " << hltBitWords.size() << " HLT bit words");
-
   return StatusCode::SUCCESS;
 }
 
diff --git a/Trigger/TrigSteer/TrigOutputHandling/CMakeLists.txt b/Trigger/TrigSteer/TrigOutputHandling/CMakeLists.txt
index 340aaa763917d4c3e67511ca20a3f10f4325b0ca..3de74f1f2f4a298fb89b2aab732ca7f389a057ae 100644
--- a/Trigger/TrigSteer/TrigOutputHandling/CMakeLists.txt
+++ b/Trigger/TrigSteer/TrigOutputHandling/CMakeLists.txt
@@ -34,6 +34,7 @@ atlas_depends_on_subdirs( PUBLIC
                           Trigger/TrigConfiguration/TrigConfIO
                           Control/AthContainersRoot)
 
+
 find_package( tdaq-common COMPONENTS eformat )
 find_package( Boost )
 
diff --git a/Trigger/TrigSteer/TrigOutputHandling/TrigOutputHandling/HLTResultMTMakerTool.h b/Trigger/TrigSteer/TrigOutputHandling/TrigOutputHandling/HLTResultMTMakerTool.h
index b98b34d85979fc6251695b27a348d358b532920d..7027790ee7efdd353cb783e04f0dfcb1b86d68ee 100644
--- a/Trigger/TrigSteer/TrigOutputHandling/TrigOutputHandling/HLTResultMTMakerTool.h
+++ b/Trigger/TrigSteer/TrigOutputHandling/TrigOutputHandling/HLTResultMTMakerTool.h
@@ -5,7 +5,10 @@
 #define TRIGOUTPUTHANDLING_HLTRESULTMTMAKERTOOL_H
 
 #include "GaudiKernel/IAlgTool.h"
+#include "GaudiKernel/EventContext.h"
+
 #include "TrigSteeringEvent/HLTResultMT.h"
+
 /**
  * @class HLTResultMTMakerTool
  * @brief Base class for AlgTools filling information in an HLTResultMT object
@@ -14,7 +17,7 @@ class HLTResultMTMakerTool : virtual public IAlgTool {
 public: 
   DeclareInterfaceID(HLTResultMTMakerTool, 1, 0);
 
-  virtual StatusCode fill( HLT::HLTResultMT& resultToFill ) const = 0; //TODO: pass EventContext& explicitly as argument
+  virtual StatusCode fill( HLT::HLTResultMT& resultToFill, const EventContext& ctx ) const = 0;
   
   virtual ~HLTResultMTMakerTool() override {}
 }; 
diff --git a/Trigger/TrigSteer/TrigOutputHandling/TrigOutputHandling/ITriggerBitsMakerTool.h b/Trigger/TrigSteer/TrigOutputHandling/TrigOutputHandling/ITriggerBitsMakerTool.h
new file mode 100644
index 0000000000000000000000000000000000000000..03618a31db729399df5590e8c0bf177063f680f6
--- /dev/null
+++ b/Trigger/TrigSteer/TrigOutputHandling/TrigOutputHandling/ITriggerBitsMakerTool.h
@@ -0,0 +1,28 @@
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+#ifndef TRIGOUTPUTHANDLING_ITRIGGERBITSMAKERTOOL_H
+#define TRIGOUTPUTHANDLING_ITRIGGERBITSMAKERTOOL_H
+
+#include "GaudiKernel/IAlgTool.h"
+#include "GaudiKernel/EventContext.h"
+
+#include <boost/dynamic_bitset.hpp>
+
+/**
+ * @class ITriggerBitsMakerTool
+ * @brief Base class for AlgTools providing a getBits interface to generate trigger bits
+ **/
+class ITriggerBitsMakerTool : virtual public IAlgTool {
+public: 
+  DeclareInterfaceID(ITriggerBitsMakerTool, 1, 0);
+
+  virtual StatusCode getBits(boost::dynamic_bitset<uint32_t>& passRaw,
+    boost::dynamic_bitset<uint32_t>& prescaled,
+    boost::dynamic_bitset<uint32_t>& rerun,
+    const EventContext& ctx) const = 0;
+
+  virtual ~ITriggerBitsMakerTool() override {}
+}; 
+
+#endif // TRIGOUTPUTHANDLING_ITRIGGERBITSMAKERTOOL_H
diff --git a/Trigger/TrigSteer/TrigOutputHandling/TrigOutputHandling/TriggerBitsMakerTool.h b/Trigger/TrigSteer/TrigOutputHandling/TrigOutputHandling/TriggerBitsMakerTool.h
index c0df31d223e0cd25cf19705ffadf5889f961fdde..95671b8eb3f5b33952e72301e21a71f9a52914ce 100644
--- a/Trigger/TrigSteer/TrigOutputHandling/TrigOutputHandling/TriggerBitsMakerTool.h
+++ b/Trigger/TrigSteer/TrigOutputHandling/TrigOutputHandling/TriggerBitsMakerTool.h
@@ -8,32 +8,55 @@
 #include "DecisionHandling/TrigCompositeUtils.h"
 #include "AthenaBaseComps/AthAlgTool.h"
 #include "TrigOutputHandling/HLTResultMTMakerTool.h"
-
+#include "TrigOutputHandling/ITriggerBitsMakerTool.h"
+#include "TrigConfData/HLTMenu.h"
 
 /**
  * @class TriggerBitsMakerTool
- * @brief fills trigger bits in the HLTResultMT object
+ * @brief Obtains trigger bits from Navigation summary via getBits and (online) fills trigger bits in the HLTResultMT object
  **/
-class TriggerBitsMakerTool : public extends<AthAlgTool, HLTResultMTMakerTool> {
+class TriggerBitsMakerTool : public extends<AthAlgTool, HLTResultMTMakerTool, ITriggerBitsMakerTool> {
 public:
   TriggerBitsMakerTool(const std::string& type, const std::string& name, const IInterface* parent);
   virtual ~TriggerBitsMakerTool() override;
 
-  virtual StatusCode fill( HLT::HLTResultMT& resultToFill ) const override;
-  StatusCode fill( std::vector<uint32_t>& place ) const;
+  virtual StatusCode fill( HLT::HLTResultMT& resultToFill, const EventContext& ctx ) const override;
+
+  virtual StatusCode getBits(boost::dynamic_bitset<uint32_t>& passRaw,
+    boost::dynamic_bitset<uint32_t>& prescaled,
+    boost::dynamic_bitset<uint32_t>& rerun,
+    const EventContext& ctx) const override;
   
   virtual StatusCode initialize() override;
-  virtual StatusCode finalize() override;
+  virtual StatusCode start() override;
 
 private:
-  SG::ReadHandleKey<TrigCompositeUtils::DecisionContainer> m_finalChainDecisions { this, "ChainDecisions", "HLTNav_Summary", "Container with final chain decisions"  }; 
+  enum BitCategory{ HLTPassRawCategory, HLTPrescaledCategory, HLTRerunCategory };
+
+  StatusCode setBit(const TrigCompositeUtils::DecisionID chain, const BitCategory category, boost::dynamic_bitset<uint32_t>& resultToFill) const;
+
+  /**
+   * @brief Check that a chain's hash in the menu JSON (via python) agrees with the C++ implementation
+   **/
+  StatusCode hashConsistencyCheck(const std::string& chain, const size_t hash) const;
+
+  /**
+   * @brief Check that no existing key maps to a given value
+   **/
+  StatusCode preInsertCheck(const std::string& chain, const uint32_t bit) const;
+
+  SG::ReadHandleKey<TrigCompositeUtils::DecisionContainer> m_finalChainDecisions { this, "ChainDecisions", "HLTNav_Summary",
+    "Container with final chain decisions"  };
 
-  Gaudi::Property<std::map<std::string, int>> m_chainToStreamProperty { this, "ChainToBit", {}, "Mapping from the chain name to bit position in trigger bits array"};
+  SG::ReadHandleKey<TrigConf::HLTMenu> m_HLTMenuKey{this, "HLTTriggerMenu", "DetectorStore+HLTTriggerMenu", "HLT Menu"};
 
-  typedef std::map< TrigCompositeUtils::DecisionID, int> ChainToBitMap;
-  ChainToBitMap m_mapping;
+  Gaudi::Property<std::map<std::string, uint32_t>> m_extraChainToBit { this, "ExtraChainToBit", {},
+    "Special case and testing purposes hard-coded chain-to-bit mappings to use in addition to those from the HLT menu."};
 
+  typedef std::map< TrigCompositeUtils::DecisionID, uint32_t> ChainToBitMap;
+  ChainToBitMap m_mapping; //!< Mapping of each chain's hash ID to its chain counter
 
+  uint32_t m_largestBit; //!< Largest chain counter hence largest bit needed to be stored in result bitmap
 };
 
 #endif // TRIGOUTPUTHANDLING_TRIGGERBITSMAKERTOOL_H
diff --git a/Trigger/TrigSteer/TrigOutputHandling/src/HLTResultMTMaker.cxx b/Trigger/TrigSteer/TrigOutputHandling/src/HLTResultMTMaker.cxx
index ab709e020ff277e5497597af3bb97fa1389a0926..c67390928b88b0e2715ddc648ae6a80b31acb47b 100644
--- a/Trigger/TrigSteer/TrigOutputHandling/src/HLTResultMTMaker.cxx
+++ b/Trigger/TrigSteer/TrigOutputHandling/src/HLTResultMTMaker.cxx
@@ -136,7 +136,7 @@ StatusCode HLTResultMTMaker::makeResult(const EventContext& eventContext) const
   auto time =  Monitored::Timer("TIME_build" );
   StatusCode finalStatus = StatusCode::SUCCESS;
   for (auto& maker: m_makerTools) {
-    if (StatusCode sc = maker->fill(*hltResult); sc.isFailure()) {
+    if (StatusCode sc = maker->fill(*hltResult, eventContext); sc.isFailure()) {
       ATH_MSG_ERROR(maker->name() << " failed");
       finalStatus = sc;
     }
@@ -149,7 +149,9 @@ StatusCode HLTResultMTMaker::makeResult(const EventContext& eventContext) const
 
   // Fill monitoring histograms
   auto nstreams = Monitored::Scalar("nstreams", hltResult->getStreamTags().size());
-  auto bitWords = Monitored::Scalar("bitWords", hltResult->getHltBits().size());
+  auto bitWords = Monitored::Scalar("bitWords", hltResult->getHltPassRawBits().size() 
+    + hltResult->getHltPrescaledBits().size()
+    + hltResult->getHltRerunBits().size() );
   auto nfrags   = Monitored::Scalar("nfrags",   hltResult->getSerialisedData().size());
   auto sizeMain = Monitored::Scalar("sizeMain", -1.);
   auto iter = hltResult->getSerialisedData().find(0); // this is the main fragment of the HLT result
diff --git a/Trigger/TrigSteer/TrigOutputHandling/src/StreamTagMakerTool.cxx b/Trigger/TrigSteer/TrigOutputHandling/src/StreamTagMakerTool.cxx
index bf6e066d124b149a57198d61690b9ecf1eece6e7..8728a27e16ecb67df47c19c28ff0964d28794e4c 100644
--- a/Trigger/TrigSteer/TrigOutputHandling/src/StreamTagMakerTool.cxx
+++ b/Trigger/TrigSteer/TrigOutputHandling/src/StreamTagMakerTool.cxx
@@ -73,10 +73,10 @@ StatusCode StreamTagMakerTool::finalize() {
 
 // =============================================================================
 
-StatusCode StreamTagMakerTool::fill( HLT::HLTResultMT& resultToFill ) const {
+StatusCode StreamTagMakerTool::fill( HLT::HLTResultMT& resultToFill, const EventContext& ctx ) const {
   // obtain chain decisions,
   using namespace TrigCompositeUtils;
-  auto chainsHandle = SG::makeHandle( m_finalChainDecisions );
+  auto chainsHandle = SG::makeHandle( m_finalChainDecisions, ctx );
   if (!chainsHandle.isValid()) {
     ATH_MSG_ERROR("Unable to read in the HLTNav_Summary from the DecisionSummaryMakerAlg");
     return StatusCode::FAILURE;
@@ -106,7 +106,7 @@ StatusCode StreamTagMakerTool::fill( HLT::HLTResultMT& resultToFill ) const {
   decisionIDs(rerunChains, rerunIDs);
 
   std::unordered_map<unsigned int, PEBInfoWriterToolBase::PEBInfo> chainToPEBInfo;
-  ATH_CHECK(fillPEBInfoMap(chainToPEBInfo));
+  ATH_CHECK(fillPEBInfoMap(chainToPEBInfo, ctx));
 
   // for each accepted chain lookup the map of chainID -> ST
   for ( DecisionID chain: passRawIDs ) {
@@ -151,10 +151,10 @@ StatusCode StreamTagMakerTool::fill( HLT::HLTResultMT& resultToFill ) const {
 
 // =============================================================================
 
-StatusCode StreamTagMakerTool::fillPEBInfoMap(std::unordered_map<DecisionID, PEBInfoWriterToolBase::PEBInfo>& map) const {
+StatusCode StreamTagMakerTool::fillPEBInfoMap(std::unordered_map<DecisionID, PEBInfoWriterToolBase::PEBInfo>& map, const EventContext& ctx) const {
   for (const auto& key: m_pebDecisionKeys) {
     // Retrieve the decision container
-    auto handle = SG::makeHandle(key); //TODO: pass EventContext& explicitly here
+    auto handle = SG::makeHandle(key, ctx); //TODO: pass EventContext& explicitly here
     if (not handle.isValid())  {
       ATH_MSG_DEBUG("Missing input " <<  key.key() << " likely rejected");
       continue;
diff --git a/Trigger/TrigSteer/TrigOutputHandling/src/StreamTagMakerTool.h b/Trigger/TrigSteer/TrigOutputHandling/src/StreamTagMakerTool.h
index a652a67ecc427e1b3f1256b108d906c8130040de..15298e269f0b64f43595a15c98aa2f380c5b29ab 100644
--- a/Trigger/TrigSteer/TrigOutputHandling/src/StreamTagMakerTool.h
+++ b/Trigger/TrigSteer/TrigOutputHandling/src/StreamTagMakerTool.h
@@ -31,7 +31,7 @@ public:
   StreamTagMakerTool(const std::string& type, const std::string& name, const IInterface* parent);
   virtual ~StreamTagMakerTool() override;
 
-  virtual StatusCode fill( HLT::HLTResultMT& resultToFill ) const override;
+  virtual StatusCode fill( HLT::HLTResultMT& resultToFill, const EventContext& ctx ) const override;
 
   virtual StatusCode initialize() override;
 
@@ -53,14 +53,11 @@ private:
   Gaudi::Property<bool> m_allowRerunChains {this, "AllowRerunChains", false,
     "Normally false, but if set to true this will allow resurrected chains which ran in the second pass to also add stream tags"};
 
-  Gaudi::Property<std::string> m_menuJSON {this, "HLTmenuFile", "UNSET",
-    "Filename of just-generated HLT Menu JSON used to configure the TriggerBitsMakerTool"};
-
   /// Chain to streams map filled from the HLT Menu JSON
   std::unordered_map<TrigCompositeUtils::DecisionID, std::vector<StreamTagInfo> > m_mapping;
 
   /// Helper method to fill the chainID->PEBInfo map
-  StatusCode fillPEBInfoMap(std::unordered_map<TrigCompositeUtils::DecisionID, PEBInfoWriterToolBase::PEBInfo>& map) const;
+  StatusCode fillPEBInfoMap(std::unordered_map<TrigCompositeUtils::DecisionID, PEBInfoWriterToolBase::PEBInfo>& map, const EventContext& ctx) const;
 };
 
 /// operator<< for StreamTagInfo
diff --git a/Trigger/TrigSteer/TrigOutputHandling/src/TriggerBitsMakerTool.cxx b/Trigger/TrigSteer/TrigOutputHandling/src/TriggerBitsMakerTool.cxx
index 9e03585539b211c92af889119939be4b27704578..8f735d27ecb098262e4b24d70bbe0a144643bd43 100644
--- a/Trigger/TrigSteer/TrigOutputHandling/src/TriggerBitsMakerTool.cxx
+++ b/Trigger/TrigSteer/TrigOutputHandling/src/TriggerBitsMakerTool.cxx
@@ -3,6 +3,9 @@
 */
 #include "DecisionHandling/HLTIdentifier.h"
 #include "TrigOutputHandling/TriggerBitsMakerTool.h"
+#include "TrigConfHLTData/HLTUtils.h"
+
+#include <algorithm>
 
 TriggerBitsMakerTool::TriggerBitsMakerTool(const std::string& type, const std::string& name, const IInterface* parent) :
   base_class(type, name, parent){}
@@ -10,65 +13,185 @@ TriggerBitsMakerTool::TriggerBitsMakerTool(const std::string& type, const std::s
 TriggerBitsMakerTool::~TriggerBitsMakerTool() {}
 
 StatusCode TriggerBitsMakerTool::initialize() {
+
   ATH_CHECK( m_finalChainDecisions.initialize() );
+  ATH_CHECK( m_HLTMenuKey.initialize() );
+
+  return StatusCode::SUCCESS;
+}
 
-  for ( auto& chainAndBit: m_chainToStreamProperty ) {
-    struct { std::string chain; int bit; } conf { chainAndBit.first, chainAndBit.second };    
-    ATH_MSG_DEBUG( "Chain " << conf.chain << " will flip  " << conf.bit <<  " bit" );
-    m_mapping[ HLT::Identifier( conf.chain ) ] = conf.bit;
-    
+StatusCode TriggerBitsMakerTool::start() {
+  SG::ReadHandle<TrigConf::HLTMenu>  hltMenuHandle = SG::makeHandle( m_HLTMenuKey );
+  ATH_CHECK( hltMenuHandle.isValid() );
+  ATH_MSG_INFO("Configuring from " << m_HLTMenuKey << " with " << hltMenuHandle->size() << " chains");
+
+  m_largestBit = 0;
+  for (const TrigConf::Chain& ch : *hltMenuHandle) {
+    ATH_MSG_DEBUG( "Chain " << ch.name() << " will flip " << ch.counter() <<  " bit" );
+    ATH_CHECK(preInsertCheck(ch.name(), ch.counter()));
+    ATH_CHECK(hashConsistencyCheck(ch.name(), ch.namehash()));
+    m_mapping[ HLT::Identifier( ch.name() ).numeric() ] = ch.counter();
+    m_largestBit = std::max(m_largestBit, ch.counter());
+  }
+
+  // This block allows extra mappings to be supplied by python, e.g. for testing purposes
+  for (const auto& chainAndBit: m_extraChainToBit ) {
+    struct { std::string chain; uint32_t bit; } conf { chainAndBit.first, chainAndBit.second };    
+    ATH_MSG_DEBUG( "Extra Chain " << conf.chain << " will flip  " << conf.bit <<  " bit" );
+    ATH_CHECK(preInsertCheck(conf.chain, conf.bit));
+    m_mapping[ HLT::Identifier( conf.chain ).numeric() ] = conf.bit;
+    m_largestBit = std::max(m_largestBit, conf.bit);
   }
 
   return StatusCode::SUCCESS;
 }
 
 
-StatusCode TriggerBitsMakerTool::fill( HLT::HLTResultMT& resultToFill ) const {
-  auto chainsHandle = SG::makeHandle( m_finalChainDecisions );
-  if (!chainsHandle.isValid()) {
-    ATH_MSG_ERROR("Unable to read in the HLTNav_Summary from the DecisionSummaryMakerAlg");
+StatusCode TriggerBitsMakerTool::hashConsistencyCheck(const std::string& chain, const size_t hash) const {
+  if (HLT::Identifier( chain ).numeric() != hash) {
+    ATH_MSG_ERROR("Inconsistent hashes found for chain:" << chain << ", from Python:" << hash
+      << ", from C++:" << HLT::Identifier( chain ).numeric());
+    return StatusCode::FAILURE;
+  }
+  return StatusCode::SUCCESS;
+}
+
+StatusCode TriggerBitsMakerTool::preInsertCheck(const std::string& chain, const uint32_t bit) const {
+  const auto checkIt = std::find_if(
+    m_mapping.begin(), m_mapping.end(),
+    [&](const std::pair<TrigCompositeUtils::DecisionID, uint32_t>& m) { return m.second == bit; }
+  );
+  if (checkIt != m_mapping.end()) {
+    ATH_MSG_ERROR( "Multiple chains " << TrigConf::HLTUtils::hash2string(checkIt->first) 
+      << " and " << chain << " are both configured with ChainCounter:" << bit);
     return StatusCode::FAILURE;
   }
+  return StatusCode::SUCCESS;
+}
 
-  const TrigCompositeUtils::Decision* passRawChains = nullptr;
-  for (const TrigCompositeUtils::Decision* d : *chainsHandle) {
-    if (d->name() == "HLTPassRaw") {
-      passRawChains = d;
+StatusCode TriggerBitsMakerTool::getBits(boost::dynamic_bitset<uint32_t>& passRaw,
+  boost::dynamic_bitset<uint32_t>& prescaled,
+  boost::dynamic_bitset<uint32_t>& rerun,
+  const EventContext& ctx) const
+{
+  using namespace TrigCompositeUtils;
+
+  passRaw.clear();
+  prescaled.clear();
+  rerun.clear();
+
+  passRaw.resize(m_largestBit + 1);
+  prescaled.resize(m_largestBit + 1);
+  rerun.resize(m_largestBit + 1);
+
+  auto chainsHandle = SG::makeHandle(m_finalChainDecisions, ctx);
+  ATH_CHECK(chainsHandle.isValid());
+
+  const Decision* HLTPassRaw = nullptr;
+  const Decision* HLTPrescaled = nullptr;
+  const Decision* HLTRerun = nullptr;
+
+  DecisionIDContainer passRawIDs; //!< The chains which returned a positive decision
+  DecisionIDContainer prescaledIDs; //!< The chains which did not run due to being prescaled out
+  DecisionIDContainer rerunIDs; //!< The chains which were activate only in the rerun (not physics decisions)
+
+  // Read the sets of chain IDs
+  for (const Decision* decisionObject : *chainsHandle) {
+    // Collect all decisions (IDs of passed/prescaled/rerun chains) from named decisionObjects
+    if (decisionObject->name() == "HLTPassRaw") {
+      HLTPassRaw = decisionObject;
+    } else if (decisionObject->name() == "HLTPrescaled") {
+      HLTPrescaled = decisionObject;
+    } else if (decisionObject->name() == "HLTRerun") {
+      HLTRerun = decisionObject;
+    }
+    if (HLTPassRaw && HLTPrescaled && HLTRerun) {
       break;
     }
   }
 
-  if (passRawChains == nullptr) {
-    ATH_MSG_ERROR("Unable to read in the HLTNav_Summary from the DecisionSummaryMakerAlg");
-    return StatusCode::FAILURE;
-  }
+  ATH_CHECK(HLTPassRaw != nullptr);
+  ATH_CHECK(HLTPrescaled != nullptr);
+  ATH_CHECK(HLTRerun != nullptr);
 
-  TrigCompositeUtils::DecisionIDContainer passRawIDs;
-  TrigCompositeUtils::decisionIDs(passRawChains, passRawIDs);
+  decisionIDs(HLTPassRaw, passRawIDs);
+  decisionIDs(HLTPrescaled, prescaledIDs);
+  decisionIDs(HLTRerun, rerunIDs);
 
-  for ( TrigCompositeUtils::DecisionID chain: passRawIDs ) {
-    auto mappingIter = m_mapping.find( chain );
-    // each chain has to have stream
-    if( mappingIter == m_mapping.end() ) { 
-      ATH_MSG_ERROR("Each chain has to have the bit/counter associated whereas the " << HLT::Identifier( chain ) << " does not" );
-      return StatusCode::FAILURE;
-    }
-    const int chainBitPosition = mappingIter->second;
-    ATH_MSG_DEBUG("Setting bit " << chainBitPosition << " corresponding to chain" << HLT::Identifier(chain));
-    ATH_CHECK(resultToFill.addHltBit(chainBitPosition));
+  for ( DecisionID chain: passRawIDs ) {
+    ATH_CHECK(setBit(chain, HLTPassRawCategory, passRaw));
   }
 
-  if ( msgLvl( MSG::DEBUG ) ) {
-    ATH_MSG_DEBUG("HLT result now has " << resultToFill.getHltBits().num_blocks() << " words with trigger bits:");
-    for (const auto& w : resultToFill.getHltBitsAsWords()) ATH_MSG_DEBUG("0x" << MSG::hex << w << MSG::dec);
+  for ( DecisionID chain: prescaledIDs ) {
+    ATH_CHECK(setBit(chain, HLTPrescaledCategory, prescaled));
   }
+
+  for ( DecisionID chain: rerunIDs ) {
+    ATH_CHECK(setBit(chain, HLTRerunCategory, rerun));
+  }
+
   return StatusCode::SUCCESS;
 
 }
 
+StatusCode TriggerBitsMakerTool::fill( HLT::HLTResultMT& resultToFill, const EventContext& ctx ) const {
+
+  {
+    boost::dynamic_bitset<uint32_t> passRaw;
+    boost::dynamic_bitset<uint32_t> prescaled;
+    boost::dynamic_bitset<uint32_t> rerun;
+
+    ATH_CHECK(getBits(passRaw, prescaled, rerun, ctx));
+
+    resultToFill.setHltPassRawBits(passRaw);
+    resultToFill.setHltPrescaledBits(prescaled);
+    resultToFill.setHltRerunBits(rerun);
+  }
 
+  if ( msgLvl( MSG::DEBUG ) ) {
+    const boost::dynamic_bitset<uint32_t> passRawBits = resultToFill.getHltPassRawBits();
+    std::vector<uint32_t> bitsTemp(passRawBits.num_blocks());
+    boost::to_block_range(passRawBits, bitsTemp.begin());
+    ATH_MSG_VERBOSE("HLT result now has " << bitsTemp.size() << " words with HLT pass raw bits:");
+    for (const auto& w : bitsTemp) ATH_MSG_VERBOSE("0x" << MSG::hex << w << MSG::dec);
+    //
+    const boost::dynamic_bitset<uint32_t> prescaleBits = resultToFill.getHltPrescaledBits();
+    boost::to_block_range(prescaleBits, bitsTemp.begin());
+    ATH_MSG_VERBOSE("HLT result now has " << bitsTemp.size() << " words with HLT prescale bits:");
+    for (const auto& w : bitsTemp) ATH_MSG_VERBOSE("0x" << MSG::hex << w << MSG::dec);
+    //
+    const boost::dynamic_bitset<uint32_t> rerunBits = resultToFill.getHltRerunBits();
+    boost::to_block_range(rerunBits, bitsTemp.begin());
+    ATH_MSG_VERBOSE("HLT result now has " << bitsTemp.size() << " words with HLT rerun bits:");
+    for (const auto& w : bitsTemp) ATH_MSG_VERBOSE("0x" << MSG::hex << w << MSG::dec);
+    //
+    ATH_MSG_DEBUG("HLT result now has " << resultToFill.getHltBitsAsWords().size() << " words with the final trigger bits:");
+    for (const auto& w : resultToFill.getHltBitsAsWords()) ATH_MSG_DEBUG("0x" << MSG::hex << w << MSG::dec);
+  }
 
-StatusCode TriggerBitsMakerTool::finalize() {
   return StatusCode::SUCCESS;
+
 }
 
+StatusCode TriggerBitsMakerTool::setBit(const TrigCompositeUtils::DecisionID chain,
+  const BitCategory category,
+  boost::dynamic_bitset<uint32_t>& resultToFill) const
+{
+  auto mappingIter = m_mapping.find( chain );
+  // each chain has to have stream
+  if( mappingIter == m_mapping.end() ) {
+    ATH_MSG_ERROR("Each chain has to have the bit/counter associated whereas the " << HLT::Identifier( chain ) << " does not" );
+    return StatusCode::FAILURE;
+  }
+  const int chainBitPosition = mappingIter->second;
+  static const std::vector<std::string> bitCategoryStr {"PassRaw","Prescaled","Rerun"};
+  ATH_MSG_DEBUG("Setting bit " << chainBitPosition << " corresponding to chain "
+    << HLT::Identifier(chain) << " in BitCategory " << bitCategoryStr.at(category));
+  switch (category) {
+    case HLTPassRawCategory: resultToFill.set(chainBitPosition); break;
+    case HLTPrescaledCategory: resultToFill.set(chainBitPosition); break;
+    case HLTRerunCategory: resultToFill.set(chainBitPosition); break;
+    default: ATH_MSG_ERROR("Unknown BitCategory"); return StatusCode::FAILURE; break;
+  }
+  return StatusCode::SUCCESS;
+}
diff --git a/Trigger/TrigSteer/TrigOutputHandling/src/TriggerEDMSerialiserTool.cxx b/Trigger/TrigSteer/TrigOutputHandling/src/TriggerEDMSerialiserTool.cxx
index 820a11307395c7d4a314f710027dd3067869b891..6289e62c7a3522572edcc9521e2d9700b19d7d11 100644
--- a/Trigger/TrigSteer/TrigOutputHandling/src/TriggerEDMSerialiserTool.cxx
+++ b/Trigger/TrigSteer/TrigOutputHandling/src/TriggerEDMSerialiserTool.cxx
@@ -238,14 +238,18 @@ StatusCode TriggerEDMSerialiserTool::serialiseContainer( void* data, const Addre
   return StatusCode::SUCCESS;
 }
 
-StatusCode TriggerEDMSerialiserTool::serialisexAODAuxContainer( void* data, const Address& address, std::vector<uint32_t>& buffer ) const {
+StatusCode TriggerEDMSerialiserTool::serialisexAODAuxContainer( void* data,
+  const Address& address,
+  std::vector<uint32_t>& buffer,
+  SGImplSvc* evtStore) const
+{
   ATH_MSG_DEBUG("xAOD Aux Contianer");
   ATH_CHECK( serialiseContainer( data, address, buffer ) );
   size_t baseSize = buffer.size();
   if ( not m_saveDynamic )
     return StatusCode::SUCCESS;
 
-  DataObject* dObj = evtStore()->accessData( address.clid, address.key );
+  DataObject* dObj = evtStore->accessData( address.clid, address.key );
   ATH_CHECK( dObj != nullptr );
   size_t nDynWritten = 0;
   ATH_CHECK( serialiseDynAux( dObj, address, buffer, nDynWritten ) );
@@ -268,7 +272,7 @@ StatusCode TriggerEDMSerialiserTool::serialiseTPContainer( void* data, const Add
   return StatusCode::SUCCESS;
 }
 
-StatusCode TriggerEDMSerialiserTool::fill( HLT::HLTResultMT& resultToFill ) const {
+StatusCode TriggerEDMSerialiserTool::fill( HLT::HLTResultMT& resultToFill, const EventContext& ctx ) const {
 
   // Leave this check until there is a justified case for appending data to an existing result
   if (not resultToFill.getSerialisedData().empty()) {
@@ -276,10 +280,13 @@ StatusCode TriggerEDMSerialiserTool::fill( HLT::HLTResultMT& resultToFill ) cons
     return StatusCode::FAILURE;
   }
 
+  SGImplSvc* evtStore = static_cast<SGImplSvc*>(Atlas::getExtendedEventContext(ctx).proxy());
+  ATH_CHECK( evtStore != nullptr );
+
   for ( const Address& address: m_toSerialise ) {
     ATH_MSG_DEBUG( "Streaming " << address.persType );
     // obtain object
-    DataObject* dObj = evtStore()->accessData( address.clid, address.key );
+    DataObject* dObj = evtStore->accessData( address.clid, address.key );
     if ( dObj == nullptr ) {
       ATH_MSG_DEBUG("Data Object with the CLID " << address.clid <<" and the key " << address.key << " is missing");
       continue;
@@ -299,7 +306,7 @@ StatusCode TriggerEDMSerialiserTool::fill( HLT::HLTResultMT& resultToFill ) cons
     if ( address.category == Address::xAODInterface ) {
       ATH_CHECK( serialiseContainer( rawptr, address, fragment ) );
     } else if ( address.category == Address::xAODAux ) {
-      ATH_CHECK(  serialisexAODAuxContainer( rawptr, address, fragment ) );
+      ATH_CHECK(  serialisexAODAuxContainer( rawptr, address, fragment, evtStore ) );
     } else if ( address.category == Address::OldTP ) {
       ATH_CHECK( serialiseTPContainer( rawptr, address, fragment ) );
     }
diff --git a/Trigger/TrigSteer/TrigOutputHandling/src/TriggerEDMSerialiserTool.h b/Trigger/TrigSteer/TrigOutputHandling/src/TriggerEDMSerialiserTool.h
index 8f3e78df473bf63e750c28032dfcfd9ad36ca008..be291721d69e422d6e2f87bfc0f537b3ef1cd338 100644
--- a/Trigger/TrigSteer/TrigOutputHandling/src/TriggerEDMSerialiserTool.h
+++ b/Trigger/TrigSteer/TrigOutputHandling/src/TriggerEDMSerialiserTool.h
@@ -42,7 +42,7 @@ class TriggerEDMSerialiserTool: public extends<AthAlgTool, HLTResultMTMakerTool>
 	     const IInterface* parent );
 
   virtual ~TriggerEDMSerialiserTool();
-  virtual StatusCode fill( HLT::HLTResultMT& resultToFill ) const override;
+  virtual StatusCode fill( HLT::HLTResultMT& resultToFill, const EventContext& ctx ) const override;
 
   virtual StatusCode  initialize() override;
 
@@ -124,7 +124,7 @@ class TriggerEDMSerialiserTool: public extends<AthAlgTool, HLTResultMTMakerTool>
    * Place inside the buffer serialised the xOAD Aux container
    * invloves selection and recording of dynamic variables
    */
-  StatusCode serialisexAODAuxContainer( void* data, const Address& address, std::vector<uint32_t>& buffer ) const;
+  StatusCode serialisexAODAuxContainer( void* data, const Address& address, std::vector<uint32_t>& buffer, SGImplSvc* evtStore ) const;
 
   /**
    * Place inside the buffer the serialised old type of container
diff --git a/Trigger/TrigSteer/TrigOutputHandling/test/schema_evolution_test.cxx b/Trigger/TrigSteer/TrigOutputHandling/test/schema_evolution_test.cxx
index 4e74ca084581de27b46ba8a5901b2ec761a51379..0c523fbbd8be7977f9ba6383fec290cbb08cb533 100644
--- a/Trigger/TrigSteer/TrigOutputHandling/test/schema_evolution_test.cxx
+++ b/Trigger/TrigSteer/TrigOutputHandling/test/schema_evolution_test.cxx
@@ -47,8 +47,11 @@ StatusCode tester( TriggerEDMSerialiserTool* ser) {
      
     auto status = ser->serialiseContainer( (void*)em, interfaceAddress, serialisedData );
     VALUE( status ) EXPECTED( StatusCode::SUCCESS );
+
+    const EventContext ctx = Gaudi::Hive::currentContext();  
+    SGImplSvc* evtStore = static_cast<SGImplSvc*>(Atlas::getExtendedEventContext(ctx).proxy());
         
-    status = ser->serialisexAODAuxContainer( (void*)emAux, auxAddress, serialisedData );
+    status = ser->serialisexAODAuxContainer( (void*)emAux, auxAddress, serialisedData, evtStore );
     VALUE( status ) EXPECTED( StatusCode::SUCCESS );  
 
     return StatusCode::SUCCESS;
@@ -79,26 +82,22 @@ int main() {
   TriggerEDMSerialiserTool* ser = dynamic_cast< TriggerEDMSerialiserTool*>(algTool);
   VALUE( ser == nullptr ) EXPECTED ( false );
 
-  VALUE( tester( ser ) ) EXPECTED( StatusCode::SUCCESS );
-
-  auto result = new HLT::HLTResultMT();
-  result->addSerialisedData( 0, serialisedData );
-
-  VALUE( pStore->record(result, "HLTResultMT") ) EXPECTED ( StatusCode::SUCCESS );
-
-
   TriggerEDMDeserialiserAlg deser ("deserialiser", pSvcLoc);  deser.addRef();
   deser.sysInitialize();
 
-  
   IProxyDict* xdict = &*deser.evtStore();
   xdict = deser.evtStore()->hiveProxyDict();
   EventContext ctx;
   ctx.setExtension( Atlas::ExtendedEventContext(xdict) );
-  Gaudi::Hive::setCurrentContext (ctx);  
-  VALUE( deser.execute( ctx ) ) EXPECTED ( StatusCode::SUCCESS );
+  Gaudi::Hive::setCurrentContext (ctx);
 
+  VALUE( tester( ser ) ) EXPECTED( StatusCode::SUCCESS );
 
-  
+  auto result = new HLT::HLTResultMT();
+  result->addSerialisedData( 0, serialisedData );
+
+  VALUE( pStore->record(result, "HLTResultMT") ) EXPECTED ( StatusCode::SUCCESS );
+
+  VALUE( deser.execute( ctx ) ) EXPECTED ( StatusCode::SUCCESS );
 
 }
diff --git a/Trigger/TrigSteer/TrigOutputHandling/test/serial_deserial_test.cxx b/Trigger/TrigSteer/TrigOutputHandling/test/serial_deserial_test.cxx
index 57b503a9e6e11e89f4c2225a95d056ad4785c108..caa395596cfa39c652f7356d13190722e123e1a2 100644
--- a/Trigger/TrigSteer/TrigOutputHandling/test/serial_deserial_test.cxx
+++ b/Trigger/TrigSteer/TrigOutputHandling/test/serial_deserial_test.cxx
@@ -70,16 +70,14 @@ int main() {
 
 
   // TDOD simplify :-) ?
-  auto runAlg = [&](TriggerEDMDeserialiserAlg& alg) {
-    IProxyDict* xdict = &*alg.evtStore();
-    xdict = alg.evtStore()->hiveProxyDict();
-    EventContext ctx;
-    ctx.setExtension( Atlas::ExtendedEventContext(xdict) );
-    Gaudi::Hive::setCurrentContext (ctx);
+  auto runAlg = [&](TriggerEDMDeserialiserAlg& alg, const EventContext& ctx) {
     return alg.execute( ctx );
   };
 
-
+  IProxyDict* xdict = &*deser.evtStore();
+  xdict = deser.evtStore()->hiveProxyDict();
+  EventContext ctx;
+  ctx.setExtension( Atlas::ExtendedEventContext(xdict) );
 
   for ( int rep = 0; rep < 50 ; ++ rep ) {
     testTrigEMContinerInsert(pStore);
@@ -87,13 +85,13 @@ int main() {
     testRoIDescriptorInsert(pStore);
 
     auto hltres = new HLT::HLTResultMT();
-    VALUE( ser->fill( *hltres ) ) EXPECTED ( StatusCode::SUCCESS );
+    VALUE( ser->fill( *hltres, ctx ) ) EXPECTED ( StatusCode::SUCCESS );
 
     pStore->clearStore();
     // now objects are only in serialised form in HLTResultMT object
 
     VALUE( pStore->record( hltres, "HLTResultMT" ) ) EXPECTED ( StatusCode::SUCCESS );
-    VALUE( runAlg( deser ) ) EXPECTED ( StatusCode::SUCCESS );
+    VALUE( runAlg( deser, ctx ) ) EXPECTED ( StatusCode::SUCCESS );
     //    VALUE( runAlg( deser2 ) ) EXPECTED ( StatusCode::SUCCESS );
 
     testTrigEMContinerReadAndCheck(pStore);
diff --git a/Trigger/TrigValidation/TrigUpgradeTest/share/full_menu.py b/Trigger/TrigValidation/TrigUpgradeTest/share/full_menu.py
index c29f9c169048bb473c47ca14e90d198e5489c70e..14ac1e80996008809bd61989c2a90909a69edadb 100644
--- a/Trigger/TrigValidation/TrigUpgradeTest/share/full_menu.py
+++ b/Trigger/TrigValidation/TrigUpgradeTest/share/full_menu.py
@@ -154,7 +154,7 @@ if opt.doWriteESD:
 
 if configureBSResult:
     from TrigOutputHandling.TrigOutputHandlingConfig import TriggerEDMSerialiserToolCfg
-    from TrigOutputHandling.TrigOutputHandlingConf import StreamTagMakerTool # TODO: TriggerBitsMakerTool
+    from TrigOutputHandling.TrigOutputHandlingConf import StreamTagMakerTool, TriggerBitsMakerTool
 
     # Tool serialising EDM objects to fill the HLT result
     serialiser = TriggerEDMSerialiserToolCfg('Serialiser')
@@ -165,8 +165,6 @@ if configureBSResult:
 
     # Tool adding stream tags to HLT result
     stmaker = StreamTagMakerTool()
-    stmaker.ChainDecisions = 'HLTNav_Summary'
-    stmaker.HLTmenuFile = TriggerFlags.outputHLTmenuJsonFile()
 
     # Map decisions producing PEBInfo from DecisionSummaryMakerAlg.FinalStepDecisions to StreamTagMakerTool.PEBDecisionKeys
     import AthenaCommon.AlgSequence as acas
@@ -178,10 +176,12 @@ if configureBSResult:
             __log.debug('Chain %s produces decision %s with PEBInfo', chain, decisionKey)
             stmaker.PEBDecisionKeys.append(decisionKey)
 
+    bitsmaker = TriggerBitsMakerTool()
+
     # Configure the HLT result maker to use the above tools
     from AthenaCommon.AppMgr import ServiceMgr as svcMgr
     hltResultMaker = svcMgr.HltEventLoopMgr.ResultMaker
-    hltResultMaker.MakerTools = [stmaker, serialiser] # TODO: add bits maker
+    hltResultMaker.MakerTools = [stmaker, serialiser, bitsmaker]
 
 # Debugging for view cross-dependencies
 if opt.reverseViews:
diff --git a/Trigger/TriggerCommon/TriggerJobOpts/python/TriggerConfig.py b/Trigger/TriggerCommon/TriggerJobOpts/python/TriggerConfig.py
index db8e8fe7e91493d0d81fa2ccbf40ddabc5855f3e..4deb306a6d7656a2ed87f19e3a61f51bd489ce81 100644
--- a/Trigger/TriggerCommon/TriggerJobOpts/python/TriggerConfig.py
+++ b/Trigger/TriggerCommon/TriggerJobOpts/python/TriggerConfig.py
@@ -219,10 +219,8 @@ def triggerBSOutputCfg( flags, decObj ):
     """
     acc = ComponentAccumulator()
 
-
-
     from TrigEDMConfig.TriggerEDMRun3 import TriggerHLTListRun3, persistent
-    from TrigOutputHandling.TrigOutputHandlingConf import HLTResultMTMakerAlg # , StreamTagMakerTool, TriggerBitsMakerTool     # TODO add config of these two
+    from TrigOutputHandling.TrigOutputHandlingConf import HLTResultMTMakerAlg#, TriggerBitsMakerTool, StreamTagMakerTool
     from TrigOutputHandling.TrigOutputHandlingConfig import TriggerEDMSerialiserToolCfg, HLTResultMTMakerCfg
     
     serialiser = TriggerEDMSerialiserToolCfg("Serialiser")
@@ -237,15 +235,12 @@ def triggerBSOutputCfg( flags, decObj ):
         serialisedTypeColl="{}#{}".format(persistent(typeName), collName)
         __log.info( "Serialising {}".format( serialisedTypeColl ) ) 
         serialiser.addCollectionListToMainResult( [ serialisedTypeColl ] )
-        
-        
-    # not configuring the two tools below now as we soon will change method to configure them (via TrigConfigSvc)
-    #stmaker                       = StreamTagMakerTool()
-    #bitsmaker                     = TriggerBitsMakerTool()
-    
-    
+
+
     hltResultMakerTool            = HLTResultMTMakerCfg("MakerTool") # want short nme to see in the log
-    hltResultMakerTool.MakerTools = [ serialiser ] #, stmaker, bitsmaker ] 
+    hltResultMakerTool.MakerTools = [ serialiser ] 
+    # This should be the following (inc imports, above), pending 
+    #hltResultMakerTool.MakerTools = [ serialiser, StreamTagMakerTool(), TriggerBitsMakerTool() ] 
     hltResultMakerAlg             = HLTResultMTMakerAlg()
     hltResultMakerAlg.ResultMaker = hltResultMakerTool
     acc.addEventAlgo( hltResultMakerAlg )
diff --git a/Trigger/TriggerCommon/TriggerMenuMT/python/L1/Base/Items.py b/Trigger/TriggerCommon/TriggerMenuMT/python/L1/Base/Items.py
index 051fd707629f35488785eabd2643eeed6b58979a..0bbc7ed609e5b3f2672a45bcd3d4a92091174934 100644
--- a/Trigger/TriggerCommon/TriggerMenuMT/python/L1/Base/Items.py
+++ b/Trigger/TriggerCommon/TriggerMenuMT/python/L1/Base/Items.py
@@ -156,6 +156,7 @@ class MenuItem(object):
 
     def json(self):
         confObj = odict()
+        confObj["name"] = self.name
         confObj["ctpid"] = self.ctpid
         confObj["definition"] = str(self.logic)
         if self.bunchGroups: