diff --git a/Projects/AnalysisBase/package_filters.txt b/Projects/AnalysisBase/package_filters.txt
index 6c7c2e836e82bf94d99461e507bbdfd51c0b8b30..274072529144919e58a7912e9b1cea9cfc2db2e6 100644
--- a/Projects/AnalysisBase/package_filters.txt
+++ b/Projects/AnalysisBase/package_filters.txt
@@ -116,6 +116,7 @@
 + Trigger/TrigConfiguration/TrigConfHLTUtils
 + Trigger/TrigConfiguration/TrigConfInterfaces
 + Trigger/TrigConfiguration/TrigConfL1Data
++ Trigger/TrigConfiguration/TrigConfData
 + Trigger/TrigConfiguration/TrigConfxAOD
 + Trigger/TrigEvent/TrigDecisionInterface
 + Trigger/TrigEvent/TrigNavStructure
diff --git a/Reconstruction/RecExample/RecExPers/share/RecoOutputMetadataList_jobOptions.py b/Reconstruction/RecExample/RecExPers/share/RecoOutputMetadataList_jobOptions.py
index fad08cd70eaa31018277e5b185c71b3bf2c420fd..0918ec942bb21ff03ecf940c90f4913915b3ae13 100644
--- a/Reconstruction/RecExample/RecExPers/share/RecoOutputMetadataList_jobOptions.py
+++ b/Reconstruction/RecExample/RecExPers/share/RecoOutputMetadataList_jobOptions.py
@@ -13,6 +13,8 @@ if metadata['eventTypes'][0] == 'IS_SIMULATION' \
 recoMetadataItemList = CfgItemList("RecoMetadata",
                                     items = ["xAOD::TriggerMenuContainer#*",
                                              "xAOD::TriggerMenuAuxContainer#*",
+                                             "xAOD::TriggerMenuJsonContainer#*",
+                                             "xAOD::TriggerMenuJsonAuxContainer#*",
                                              "IOVMetaDataContainer#*",
                                              "xAOD::LumiBlockRangeContainer#*",
 	                                     "xAOD::LumiBlockRangeAuxContainer#*",
diff --git a/Trigger/TrigConfiguration/TrigConfData/CMakeLists.txt b/Trigger/TrigConfiguration/TrigConfData/CMakeLists.txt
index 03bfa94ae99dcd291fffc95c338c08a47c03289b..33e0694865612efdeba2e96808e8000fbd5771b3 100644
--- a/Trigger/TrigConfiguration/TrigConfData/CMakeLists.txt
+++ b/Trigger/TrigConfiguration/TrigConfData/CMakeLists.txt
@@ -3,6 +3,12 @@
 # Declare the package name:
 atlas_subdir( TrigConfData )
 
+# Extra dependencies, based on the environment:
+set( extra_libs )
+if( NOT XAOD_STANDALONE )
+   set( extra_libs AthenaKernel )
+endif()
+
 # External dependencies:
 find_package( Boost )
 
@@ -12,7 +18,7 @@ atlas_add_library ( TrigConfData
                     TrigConfData/*.h src/*.cxx
                     PUBLIC_HEADERS TrigConfData
                     INCLUDE_DIRS ${Boost_INCLUDE_DIRS} 
-                    LINK_LIBRARIES ${Boost_LIBRARIES} AthenaKernel CxxUtils
+                    LINK_LIBRARIES ${Boost_LIBRARIES} ${extra_libs} CxxUtils
                     )
 
 # standalone library for use by detector software:
diff --git a/Trigger/TrigConfiguration/TrigConfData/TrigConfData/DataStructure.h b/Trigger/TrigConfiguration/TrigConfData/TrigConfData/DataStructure.h
index 29b2a9d3622fe9d8356c6acf3838c733d472041f..33dbd009dc9bf801b1b60fea729b20e5c2b15864 100644
--- a/Trigger/TrigConfiguration/TrigConfData/TrigConfData/DataStructure.h
+++ b/Trigger/TrigConfiguration/TrigConfData/TrigConfData/DataStructure.h
@@ -223,6 +223,7 @@ namespace TrigConf {
 }
 
 #ifndef TRIGCONF_STANDALONE
+#ifndef XAOD_STANDALONE
 
 #include "AthenaKernel/CLASS_DEF.h" 
 CLASS_DEF( TrigConf::DataStructure , 98904516 , 1 )
@@ -231,6 +232,7 @@ CLASS_DEF( TrigConf::DataStructure , 98904516 , 1 )
 CONDCONT_DEF( TrigConf::DataStructure , 265887802 );
 
 #endif
+#endif
 
 
 #endif
diff --git a/Trigger/TrigConfiguration/TrigConfData/TrigConfData/HLTMenu.h b/Trigger/TrigConfiguration/TrigConfData/TrigConfData/HLTMenu.h
index 628e64a4e117a4cd611ed095b54fbd53162d82df..5dcac70ba05d1aa962a00cbf139785f4ae427b13 100644
--- a/Trigger/TrigConfiguration/TrigConfData/TrigConfData/HLTMenu.h
+++ b/Trigger/TrigConfiguration/TrigConfData/TrigConfData/HLTMenu.h
@@ -80,6 +80,7 @@ namespace TrigConf {
 }
 
 #ifndef TRIGCONF_STANDALONE
+#ifndef XAOD_STANDALONE
 
 #include "AthenaKernel/CLASS_DEF.h"
 CLASS_DEF( TrigConf::HLTMenu , 24176960 , 1 )
@@ -87,6 +88,7 @@ CLASS_DEF( TrigConf::HLTMenu , 24176960 , 1 )
 #include "AthenaKernel/CondCont.h"
 CONDCONT_DEF( TrigConf::HLTMenu , 155284098 );
 
+#endif
 #endif
 
 #endif
diff --git a/Trigger/TrigConfiguration/TrigConfData/TrigConfData/HLTPrescalesSet.h b/Trigger/TrigConfiguration/TrigConfData/TrigConfData/HLTPrescalesSet.h
index 5845a78f5ec5b46a63ea1fe18cd91cfb45d9a2c4..42b98372994a8b085e1edac1244230f5e55b43bc 100644
--- a/Trigger/TrigConfiguration/TrigConfData/TrigConfData/HLTPrescalesSet.h
+++ b/Trigger/TrigConfiguration/TrigConfData/TrigConfData/HLTPrescalesSet.h
@@ -74,6 +74,7 @@ namespace TrigConf {
 }
 
 #ifndef TRIGCONF_STANDALONE
+#ifndef XAOD_STANDALONE
 
 #include "AthenaKernel/CLASS_DEF.h"
 CLASS_DEF( TrigConf::HLTPrescalesSet , 134177107 , 1 )
@@ -81,6 +82,7 @@ CLASS_DEF( TrigConf::HLTPrescalesSet , 134177107 , 1 )
 #include "AthenaKernel/CondCont.h"
 CONDCONT_DEF( TrigConf::HLTPrescalesSet , 130966407 );
 
+#endif
 #endif
 
 #endif
diff --git a/Trigger/TrigConfiguration/TrigConfData/TrigConfData/L1Menu.h b/Trigger/TrigConfiguration/TrigConfData/TrigConfData/L1Menu.h
index 719e4ed293f383dc90870483347b2fcf45c376fc..8bf39b073a6f486b60c60d2ce6cf9acf086bde8a 100644
--- a/Trigger/TrigConfiguration/TrigConfData/TrigConfData/L1Menu.h
+++ b/Trigger/TrigConfiguration/TrigConfData/TrigConfData/L1Menu.h
@@ -176,6 +176,7 @@ namespace TrigConf {
 }
 
 #ifndef TRIGCONF_STANDALONE
+#ifndef XAOD_STANDALONE
 
 #include "AthenaKernel/CLASS_DEF.h"
 CLASS_DEF( TrigConf::L1Menu , 26419484 , 1 )
@@ -183,6 +184,7 @@ CLASS_DEF( TrigConf::L1Menu , 26419484 , 1 )
 #include "AthenaKernel/CondCont.h"
 CONDCONT_DEF( TrigConf::L1Menu , 11747932 );
 
+#endif
 #endif
 
 #endif
diff --git a/Trigger/TrigConfiguration/TrigConfData/TrigConfData/L1PrescalesSet.h b/Trigger/TrigConfiguration/TrigConfData/TrigConfData/L1PrescalesSet.h
index 54af67b0f445a3ecdbeaab057e76c1b7380f0f81..553b647807dc9a5a7625edd7de6164b9a80fe6b3 100644
--- a/Trigger/TrigConfiguration/TrigConfData/TrigConfData/L1PrescalesSet.h
+++ b/Trigger/TrigConfiguration/TrigConfData/TrigConfData/L1PrescalesSet.h
@@ -69,6 +69,7 @@ namespace TrigConf {
 }
 
 #ifndef TRIGCONF_STANDALONE
+#ifndef XAOD_STANDALONE
 
 #include "AthenaKernel/CLASS_DEF.h"
 CLASS_DEF( TrigConf::L1PrescalesSet , 146597935 , 1 )
@@ -76,6 +77,7 @@ CLASS_DEF( TrigConf::L1PrescalesSet , 146597935 , 1 )
 #include "AthenaKernel/CondCont.h"
 CONDCONT_DEF( TrigConf::L1PrescalesSet , 124562173 );
 
+#endif
 #endif
 
 #endif
diff --git a/Trigger/TrigConfiguration/TrigConfData/TrigConfData/TSCheckMacros.h b/Trigger/TrigConfiguration/TrigConfData/TrigConfData/TSCheckMacros.h
index d97b27266891d43a9c5031ac796b0836fb919172..a329c66ba5d92ee388758827a21a749ecee46c4f 100644
--- a/Trigger/TrigConfiguration/TrigConfData/TrigConfData/TSCheckMacros.h
+++ b/Trigger/TrigConfiguration/TrigConfData/TrigConfData/TSCheckMacros.h
@@ -11,12 +11,16 @@
 #define ATLAS_THREAD_SAFE [[gnu::thread_safe]]
 #else
 #define ATLAS_THREAD_SAFE
-#endif
+#endif // ATLAS_GCC_CHECKERS
 
 #else
 
+#ifdef XAOD_STANDALONE
+#define ATLAS_THREAD_SAFE
+#else
 #include "CxxUtils/checker_macros.h"
+#endif // XAOD_STANDALONE
 
-#endif
+#endif // TRIGCONF_STANDALONE
 
-#endif
+#endif // TRIGCONFDATA_TSCHECKMACROS_H
diff --git a/Trigger/TrigConfiguration/TrigConfxAOD/CMakeLists.txt b/Trigger/TrigConfiguration/TrigConfxAOD/CMakeLists.txt
index 31390aa07cfd5871b1648fde13d68fd7a87cbfda..378908ea5814d47d35ca8a1ad4b55dbe61605e8c 100644
--- a/Trigger/TrigConfiguration/TrigConfxAOD/CMakeLists.txt
+++ b/Trigger/TrigConfiguration/TrigConfxAOD/CMakeLists.txt
@@ -3,17 +3,20 @@
 # Declare the package name:
 atlas_subdir( TrigConfxAOD )
 
+find_package( Boost )
+
 # Libraries in the package:
 atlas_add_library( TrigConfxAODLib
    TrigConfxAOD/*.h Root/*.cxx
    PUBLIC_HEADERS TrigConfxAOD
-   LINK_LIBRARIES AsgTools xAODTrigger TrigConfL1Data TrigConfHLTData
+   INCLUDE_DIRS ${Boost_INCLUDE_DIRS}
+   LINK_LIBRARIES AsgTools xAODTrigger TrigConfL1Data TrigConfHLTData TrigConfData ${Boost_LIBRARIES}
    TrigConfInterfaces )
 
 if( NOT XAOD_STANDALONE )
    atlas_add_component( TrigConfxAOD
       src/*.h src/*.cxx src/components/*.cxx
-      LINK_LIBRARIES AthenaBaseComps AthenaKernel StoreGateLib GaudiKernel TrigConfData
+      LINK_LIBRARIES AthenaBaseComps AthenaKernel StoreGateLib GaudiKernel 
       TrigConfxAODLib )
 endif()
 
diff --git a/Trigger/TrigConfiguration/TrigConfxAOD/Root/prepareTriggerMenu.cxx b/Trigger/TrigConfiguration/TrigConfxAOD/Root/prepareTriggerMenu.cxx
index 86f3999fc2dfa295647a68d1fd5cc6a4adffe3e4..51fbb0cbcfddb0580c7577255cd22da7c5388169 100644
--- a/Trigger/TrigConfiguration/TrigConfxAOD/Root/prepareTriggerMenu.cxx
+++ b/Trigger/TrigConfiguration/TrigConfxAOD/Root/prepareTriggerMenu.cxx
@@ -16,6 +16,15 @@
 #include "TrigConfHLTData/HLTTriggerElement.h"
 #include "TrigConfHLTData/HLTSignature.h"
 
+#include "TrigConfData/HLTMenu.h"
+#include "TrigConfData/L1Menu.h"
+#include "TrigConfData/HLTPrescalesSet.h"
+#include "TrigConfData/L1PrescalesSet.h"
+#include "TrigConfData/L1BunchGroupSet.h"
+
+#include "TrigConfData/HLTChain.h"
+#include "TrigConfData/L1Item.h"
+
 // Local include(s):
 #include "TrigConfxAOD/tools/prepareTriggerMenu.h"
 
@@ -235,7 +244,7 @@ namespace TrigConf {
       }
 
       // Let the user know what happened:
-      msg << MSG::INFO << "Loaded configuration:" << endmsg;
+      msg << MSG::INFO << "Loaded xAOD::TriggerMenu configuration:" << endmsg;
       msg << MSG::INFO << "  SMK = " << menu->smk()
           << ", L1PSK = " << menu->l1psk()
           << ", HLTPSK = " << menu->hltpsk() << endmsg;
@@ -244,4 +253,131 @@ namespace TrigConf {
       return StatusCode::SUCCESS;
    }
 
+   /// Load JSON derived data into legacy structures to maintain 
+   /// compatiblity with existing code.
+   ///
+   /// @param loadedHlt The incoming HLT trigger menu object to translate
+   /// @param loadedL1 The incoming L1 trigger menu object to translate
+   /// @param loadedHltps The incoming HLT prescales menu object to translate
+   /// @param loadedL1ps The incoming L1 prescales menu object to translate
+   /// @param loadedBg The incoming bunchgroup object to translate
+   /// @param ctpConfig The LVL1 configuration object to fill
+   /// @param chainList The HLT configuration object to fill
+   /// @param bgSet The bunch structure configuration object to fill
+   /// @param msg MsgStream to print messages to
+   /// @returns <code>StatusCode::SUCCESS</code> if successful,
+   ///          <code>StatusCode::FAILURE</code> if not
+   ///
+   StatusCode prepareTriggerMenu(const HLTMenu& loadedHlt,
+                                 const L1Menu& loadedL1,
+                                 const HLTPrescalesSet& loadedHltps,
+                                 const L1PrescalesSet& loadedL1ps,
+                                 const L1BunchGroupSet& /*loadedBgSet unused so far*/,
+                                 CTPConfig& ctpConfig,
+                                 HLTChainList& chainList,
+                                 HLTSequenceList& sequenceList,
+                                 BunchGroupSet& /*bgSet unused so far*/,
+                                 MsgStream& msg ) {
+
+      // Clear the current LVL1 configuration:
+      ctpConfig.menu().clear();
+      ctpConfig.clearPrescaleSets();
+      ctpConfig.prescaleSet().resize( 512 );
+
+      // Fill the LVL1 configuration:
+      for (const L1Item& loadedItem : loadedL1) {
+         TriggerItem* item = new TriggerItem();
+         item->setName( loadedItem.name() );
+         item->setCtpId( loadedItem.ctpId() );
+         ctpConfig.menu().addTriggerItem( item );
+
+         const L1PrescalesSet::L1Prescale& loadedPrescale = loadedL1ps.prescale( loadedItem.name() );
+         ctpConfig.prescaleSet().setPrescale( loadedItem.ctpId(), static_cast< float >( loadedPrescale.prescale ) );
+         ctpConfig.prescaleSet().setPrescale( loadedItem.ctpId(), static_cast< float >( 1.0 ) );
+
+         if( msg.level() <= MSG::VERBOSE ) {
+            msg << MSG::VERBOSE << "L1 item " << loadedItem.name()
+                << " has ctpid " << loadedItem.ctpId()
+                << " and prescale " << static_cast< float >( loadedPrescale.prescale ) 
+                << endmsg;
+         }
+      }
+
+      // Clear the current HLT configuration:
+      chainList.clear();
+      sequenceList.clear();
+
+      // Fill the HLT configuration:
+      for (const Chain& loadedChain : loadedHlt) {
+         // Figure out which level this chain is from:
+         std::string level = "";
+         if( loadedChain.name().find( "L2_" ) == 0 ) {
+            level = "L2";
+         } else if( loadedChain.name().find( "EF_" ) == 0 ) {
+            level = "EF";
+         } else if( loadedChain.name().find( "HLT_" ) == 0 ) {
+            level = "HLT";
+         } else {
+            msg << MSG::WARNING << "prepareTriggerMenu(...): "
+                << "Couldn't figure out 'level' for chain: "
+                << loadedChain.name() << endmsg;
+         }
+         // An empty signature list for the chain:
+         // This is not populated from JSON data
+         std::vector< HLTSignature* > signatures;
+
+         // Create the chain object:
+         HLTChain* chain = new HLTChain( loadedChain.name(),
+                                         loadedChain.counter(),
+                                         1, // Chain version not important
+                                         level,
+                                         loadedChain.l1item(), // L1 seeds (string)
+                                         -1, // Lower chain ID not important
+                                         signatures ); // Note: Empty
+
+         const HLTPrescalesSet::HLTPrescale& loadedPrescale = loadedHltps.prescale( loadedChain.name() );
+         chain->set_rerun_prescale( -1.0 ); // Not used in R3
+         chain->set_pass_through( -1.0 );  // Not used in R3
+         chain->set_prescale( loadedPrescale.prescale );
+
+         // Add it to the list of chains:
+         if( ! chainList.addHLTChain( chain ) ) {
+            msg << MSG::FATAL << "prepareTriggerMenu(...): "
+                << "Couldn't add chain \"" << chain->name()
+                << "\"" << endmsg;
+            delete chain;
+            return StatusCode::FAILURE;
+         }
+      }
+
+      // Do not add sequence info to legacy structures (format is different)
+
+      // Bunchgroup data is TODO
+      // // Create a new BunchGroupSet object, since an existing one can't be
+      // // modified... :-/
+      // BunchGroupSet bgSetNew;
+
+      // // Fill it with info:
+      // for( size_t i = 0; i < loadedBgSet.size(); ++i ) {
+
+      //    const L1BunchGroup& loadedBg = loadedBgSet.getBunchGroup(i);
+
+      //    // Create a BunchGroup object:
+      //    BunchGroup bg;
+      //    bg.setInternalNumber( i );
+      //    // TODO - need to call  bg.addBunch( B ); for each bunch
+      //    // Might need to make some changes to L1BunchGroupSet to make this more efficient
+
+      //    // Add it to the set:
+      //     bgSetNew.addBunchGroup( bg );
+      // }
+
+      // // Replace the current bunch-group set with the new one:
+      // bgSet = bgSetNew;
+
+      // Return gracefully:
+      return StatusCode::SUCCESS;
+   }
+
+
 } // namespace TrigConf
diff --git a/Trigger/TrigConfiguration/TrigConfxAOD/Root/xAODConfigTool.cxx b/Trigger/TrigConfiguration/TrigConfxAOD/Root/xAODConfigTool.cxx
index a47c1e92e09787e8cc5999fba1ba0661e53a8df4..51b16f838ca411ef533e7222e9b88f5dfa92c9e4 100644
--- a/Trigger/TrigConfiguration/TrigConfxAOD/Root/xAODConfigTool.cxx
+++ b/Trigger/TrigConfiguration/TrigConfxAOD/Root/xAODConfigTool.cxx
@@ -11,18 +11,21 @@
 #include "TrigConfL1Data/BunchGroup.h"
 #include "TrigConfHLTData/HLTSequenceList.h"
 
-// xAOD include(s):
-#include "xAODTrigger/TrigConfKeys.h"
-
 // Local include(s):
 #include "TrigConfxAOD/xAODConfigTool.h"
 #include "TrigConfxAOD/tools/prepareTriggerMenu.h"
 #include "TrigConfxAOD/tools/xAODKeysMatch.h"
 
+// Boost includes
+#include <boost/property_tree/ptree.hpp>
+#include <boost/property_tree/json_parser.hpp>
+
 namespace TrigConf {
 
    struct xAODConfigTool::Impl
    {
+      /// Note: The run 3 JSON derives objects below are used to
+      /// additionally populate these objects for interface backwards compatibility
       /// The "translated" LVL1 configuration object
       CTPConfig m_ctpConfig;
       /// The "translated" HLT configuration object
@@ -31,15 +34,39 @@ namespace TrigConf {
       HLTSequenceList m_sequenceList;
       /// The "translated" bunch group set object
       BunchGroupSet m_bgSet;
+
+      /// The JSON decoded Run3 HLT menu 
+      HLTMenu m_currentHlt;
+      /// The JSON decoded Run3 L1 menu 
+      L1Menu m_currentL1;
+      /// The JSON decoded current HLT prescales set
+      HLTPrescalesSet m_currentHltps;
+      /// The JSON decoded current L1 prescales set
+      L1PrescalesSet m_currentL1ps;
+      /// The JSON decoded current Bunchgroup configuration
+      L1BunchGroupSet m_currentBg;
    };
 
    xAODConfigTool::xAODConfigTool( const std::string& name )
       : asg::AsgMetadataTool( name ),
-        m_tmc( 0 ), m_menu( 0 ),
+        m_tmc( nullptr ),
+        m_hltJson( nullptr), m_l1Json( nullptr ),
+        m_hltpsJson( nullptr ), m_l1psJson( nullptr ), m_bgJson( nullptr ),
+        m_menu( nullptr ),
+        m_currentHltJson( nullptr ), m_currentL1Json( nullptr ),
+        m_currentHltpsJson( nullptr ), m_currentL1psJson( nullptr ), m_currentBgJson( nullptr ),
+        m_triggerMenuContainerAvailable(false),
+        m_menuJSONContainerAvailable(false),
         m_impl (std::make_unique<Impl>()) {
 
       declareProperty( "EventObjectName", m_eventName = "TrigConfKeys" );
-      declareProperty( "MetaObjectName", m_metaName = "TriggerMenu" );
+      declareProperty( "MetaObjectName", m_metaName_run2 = "TriggerMenu" );
+
+      declareProperty( "JSONMetaObjectNameHLT", m_metaNameJSON_hlt = "TriggerMenuJson_HLT" );
+      declareProperty( "JSONMetaObjectNameL1", m_metaNameJSON_l1 = "TriggerMenuJson_L1" );
+      declareProperty( "JSONMetaObjectNameHLTPS", m_metaNameJSON_hltps = "TriggerMenuJson_HLTPS" );
+      declareProperty( "JSONMetaObjectNameL1PS", m_metaNameJSON_l1ps = "TriggerMenuJson_L1PS" );
+      declareProperty( "JSONMetaObjectNameBunchgroup", m_metaNameJSON_bg = "TriggerMenuJson_BG" );
    }
 
    xAODConfigTool::~xAODConfigTool()
@@ -51,19 +78,37 @@ namespace TrigConf {
       // Greet the user:
       ATH_MSG_INFO( "Initialising..." );
       ATH_MSG_DEBUG( "EventObjectName = " << m_eventName );
-      ATH_MSG_DEBUG( "MetaObjectName  = " << m_metaName );
+      ATH_MSG_DEBUG( "-- Run 2 AOD Configuration Settings");
+      ATH_MSG_DEBUG( "MetaObjectName  = " << m_metaName_run2 );
+      ATH_MSG_DEBUG( "-- Run 3 AOD Configuration Settings");
+      ATH_MSG_DEBUG( "JSONMetaObjectNameHLT = " << m_metaNameJSON_hlt );
+      ATH_MSG_DEBUG( "JSONMetaObjectNameL1 = " << m_metaNameJSON_l1 );
+      ATH_MSG_DEBUG( "JSONMetaObjectNameHLTPS = " << m_metaNameJSON_hltps );
+      ATH_MSG_DEBUG( "JSONMetaObjectNameL1PS = " << m_metaNameJSON_l1ps );
+      ATH_MSG_DEBUG( "JSONMetaObjectNameBunchgroup = " << m_metaNameJSON_bg );
 
       // Reset the pointers:
-      m_tmc = 0; m_menu = 0;
+      m_tmc = nullptr;
+      m_menu = nullptr;
+      //
+      m_hltJson = nullptr;
+      m_l1Json = nullptr;
+      m_hltpsJson = nullptr;
+      m_l1psJson = nullptr;
+      m_bgJson = nullptr;
+      m_currentHltJson = nullptr;
+      m_currentL1Json = nullptr;
+      m_currentHltpsJson = nullptr;
+      m_currentL1psJson = nullptr;
+      m_currentBgJson = nullptr;
 
       // Return gracefully:
       return StatusCode::SUCCESS;
    }
 
    const CTPConfig* xAODConfigTool::ctpConfig() const {
-
       // Check if the object is well prepared:
-      if( ! m_menu ) {
+      if( m_impl->m_ctpConfig.menu().size() == 0 ) {
          ATH_MSG_FATAL( "Trigger menu not loaded" );
          throw std::runtime_error( "Tool not initialised correctly" );
       }
@@ -73,9 +118,8 @@ namespace TrigConf {
    }
 
    const BunchGroupSet* xAODConfigTool::bunchGroupSet() const {
-
       // Check if the object is well prepared:
-      if( ! m_menu ) {
+      if( m_impl->m_bgSet.bunchGroups().size() == 0 ) {
          ATH_MSG_FATAL( "Trigger menu not loaded" );
          throw std::runtime_error( "Tool not initialised correctly" );
       }
@@ -85,33 +129,38 @@ namespace TrigConf {
    }
 
    uint32_t xAODConfigTool::lvl1PrescaleKey() const {
+      if ( m_menuJSONContainerAvailable ) {
 
-      // Check if the object is well prepared:
-      if( ! m_menu ) {
-         ATH_MSG_FATAL( "Trigger menu not loaded" );
-         throw std::runtime_error( "Tool not initialised correctly" );
-      }
+         return m_currentL1psJson->key();
+
+      } else {
+
+         // Check if the object is well prepared:
+         if( ! m_menu ) {
+            ATH_MSG_FATAL( "Trigger menu not loaded" );
+            throw std::runtime_error( "Tool not initialised correctly" );
+         }
 
-      // Return the key from the metadata object:
-      return m_menu->l1psk();
+         // Return the key from the metadata object:
+         return m_menu->l1psk();
+
+      }
    }
 
    const HLTChainList* xAODConfigTool::chainList() const {
-
       // Check if the object is well prepared:
-      if( ! m_menu ) {
+      if( m_impl->m_chainList.size() == 0 ) {
          ATH_MSG_FATAL( "Trigger menu not loaded" );
          throw std::runtime_error( "Tool not initialised correctly" );
       }
 
-      // Return the pointer:
+      // Return the object:
       return &m_impl->m_chainList;
    }
 
    const HLTChainList& xAODConfigTool::chains() const {
-
       // Check if the object is well prepared:
-      if( ! m_menu ) {
+      if( m_impl->m_chainList.size() == 0 ) {
          ATH_MSG_FATAL( "Trigger menu not loaded" );
          throw std::runtime_error( "Tool not initialised correctly" );
       }
@@ -121,21 +170,19 @@ namespace TrigConf {
    }
 
    const HLTSequenceList* xAODConfigTool::sequenceList() const {
-
       // Check if the object is well prepared:
-      if( ! m_menu ) {
+      if( m_impl->m_sequenceList.size() == 0 ) {
          ATH_MSG_FATAL( "Trigger menu not loaded" );
          throw std::runtime_error( "Tool not initialised correctly" );
       }
 
-      // Return the pointer:
+      // Return the object:
       return &m_impl->m_sequenceList;
    }
 
    const HLTSequenceList& xAODConfigTool::sequences() const {
-
       // Check if the object is well prepared:
-      if( ! m_menu ) {
+      if( m_impl->m_sequenceList.size() == 0 ) {
          ATH_MSG_FATAL( "Trigger menu not loaded" );
          throw std::runtime_error( "Tool not initialised correctly" );
       }
@@ -145,27 +192,81 @@ namespace TrigConf {
    }
 
    uint32_t xAODConfigTool::masterKey() const {
+      if (m_menuJSONContainerAvailable) {
 
-      // Check if the object is well prepared:
-      if( ! m_menu ) {
-         ATH_MSG_FATAL( "Trigger menu not loaded" );
+         return m_currentHltJson->key();
+
+      } else {
+
+         // Check if the object is well prepared:
+         if( ! m_menu ) {
+            ATH_MSG_FATAL( "Trigger menu not loaded" );
+            throw std::runtime_error( "Tool not initialised correctly" );
+         }
+
+         // Return the key from the metadata object:
+         return m_menu->smk();
+
+      }
+   }
+
+   uint32_t xAODConfigTool::hltPrescaleKey() const {
+      if (m_menuJSONContainerAvailable) {
+
+         return m_currentHltpsJson->key();
+
+      } else {
+
+         // Check if the object is well prepared:
+         if( ! m_menu ) {
+            ATH_MSG_FATAL( "Trigger menu not loaded" );
+            throw std::runtime_error( "Tool not initialised correctly" );
+         }
+
+         // Return the key from the metadata object:
+         return m_menu->hltpsk();
+
+      }
+   }
+
+   const HLTMenu& xAODConfigTool::hltMenu() const {
+      if( ! m_menuJSONContainerAvailable ) {
+         ATH_MSG_FATAL( "Run 3 format Trigger menu not loaded" );
          throw std::runtime_error( "Tool not initialised correctly" );
       }
+      return m_impl->m_currentHlt;
+   }
 
-      // Return the key from the metadata object:
-      return m_menu->smk();
+   const L1Menu& xAODConfigTool::l1Menu() const {
+      if( ! m_menuJSONContainerAvailable ) {
+         ATH_MSG_FATAL( "Run 3 format Trigger menu not loaded" );
+         throw std::runtime_error( "Tool not initialised correctly" );
+      }
+      return m_impl->m_currentL1;
    }
 
-   uint32_t xAODConfigTool::hltPrescaleKey() const {
+   const HLTPrescalesSet& xAODConfigTool::hltPrescalesSet() const {
+      if( ! m_menuJSONContainerAvailable ) {
+         ATH_MSG_FATAL( "Run 3 format Trigger menu not loaded" );
+         throw std::runtime_error( "Tool not initialised correctly" );
+      }
+      return m_impl->m_currentHltps;
+   }
 
-      // Check if the object is well prepared:
-      if( ! m_menu ) {
-         ATH_MSG_FATAL( "Trigger menu not loaded" );
+   const L1PrescalesSet& xAODConfigTool::l1PrescalesSet() const {
+      if( ! m_menuJSONContainerAvailable ) {
+         ATH_MSG_FATAL( "Run 3 format Trigger menu not loaded" );
          throw std::runtime_error( "Tool not initialised correctly" );
       }
+      return m_impl->m_currentL1ps;
+   }
 
-      // Return the key from the metadata object:
-      return m_menu->hltpsk();
+   const L1BunchGroupSet& xAODConfigTool::l1BunchGroupSet() const {
+      if( ! m_menuJSONContainerAvailable ) {
+         ATH_MSG_FATAL( "Run 3 format Trigger menu not loaded" );
+         throw std::runtime_error( "Tool not initialised correctly" );
+      }
+      return m_impl->m_currentBg;
    }
 
    StatusCode xAODConfigTool::beginInputFile() {
@@ -173,30 +274,107 @@ namespace TrigConf {
       // Tell the user what's happening:
       ATH_MSG_DEBUG( "Loading the trigger menu from a new input file" );
 
-      // Read the metadata object:
-      m_tmc = 0;
-      ATH_CHECK( inputMetaStore()->retrieve( m_tmc, m_metaName ) );
+      // Try to read the R2 metadata object:
+      m_tmc = nullptr;
+      m_triggerMenuContainerAvailable = true;
+      if( inputMetaStore()->retrieve( m_tmc, m_metaName_run2 ).isFailure() ) {
+         m_triggerMenuContainerAvailable = false;
+      }
+
+      // Try to read the R3 metadata object:
+      m_hltJson = nullptr;
+      m_l1Json = nullptr;
+      m_hltpsJson = nullptr;
+      m_l1psJson = nullptr;
+      m_bgJson = nullptr;
+      m_menuJSONContainerAvailable = true;
+      if( inputMetaStore()->retrieve( m_hltJson, m_metaNameJSON_hlt ).isFailure() ) {
+         m_menuJSONContainerAvailable = false;
+      }
+      if( inputMetaStore()->retrieve( m_l1Json, m_metaNameJSON_l1 ).isFailure() ) {
+         m_menuJSONContainerAvailable = false;
+      }
+      if( inputMetaStore()->retrieve( m_hltpsJson, m_metaNameJSON_hltps ).isFailure() ) {
+         m_menuJSONContainerAvailable = false;
+      }
+      if( inputMetaStore()->retrieve( m_l1psJson, m_metaNameJSON_l1ps ).isFailure() ) {
+         m_menuJSONContainerAvailable = false;
+      }
+      // if( inputMetaStore()->retrieve( m_bgJson, m_metaNameJSON_bg ).isFailure() ) {
+      //    m_menuJSONContainerAvailable = false;
+      // }
+
 
-      // A little sanity check:
-      if( ! m_tmc->size() ) {
-         // This can happen when we encounter empty input files. In which
-         // case we should not bail, but continue, and only bail if by the
-         // start of an event, we still don't see any configurations.
+      if( !m_triggerMenuContainerAvailable && !m_menuJSONContainerAvailable ) {
          ATH_MSG_WARNING( "No trigger configurations are available on "
                           "the input" );
          return StatusCode::SUCCESS;
       }
 
-      // Point the menu pointer to the first element by default:
-      m_menu = m_tmc->at( 0 );
-      // Cache the menu's configuration:
-      ATH_CHECK( prepareTriggerMenu( m_menu, m_impl->m_ctpConfig,
-                                     m_impl->m_chainList,
-                                     m_impl->m_sequenceList,
-                                     m_impl->m_bgSet, msg() ) );
+      // Prefer run three format, if available
+      if (m_menuJSONContainerAvailable) {
+
+         // A little sanity check:
+         if( m_hltJson->size() == 0 ) {
+            // This can happen when we encounter empty input files. In which
+            // case we should not bail, but continue, and only bail if by the
+            // start of an event, we still don't see any configurations.
+            ATH_MSG_WARNING( "No trigger configurations are available on "
+                             "the input" );
+            return StatusCode::SUCCESS;
+         }
+
+         // Load the first elements by default
+         ATH_CHECK( m_hltJson->size() > 0 );
+         ATH_CHECK( m_l1Json->size() > 0 );
+         ATH_CHECK( m_hltpsJson->size() > 0 );
+         ATH_CHECK( m_l1psJson->size() > 0 );
+         // ATH_CHECK( m_bgJson->size() > 0 );
+
+         m_currentHltJson = m_hltJson->at( 0 );
+         m_currentL1Json = m_l1Json->at( 0 );
+         m_currentHltpsJson = m_hltpsJson->at( 0 );
+         m_currentL1psJson = m_l1psJson->at( 0 );
+         // m_currentBgJson = m_bgJson->at( 0 );
+
+         ATH_CHECK( loadPtrees() );
+
+         ATH_CHECK( prepareTriggerMenu( m_impl->m_currentHlt,
+                                        m_impl->m_currentL1, 
+                                        m_impl->m_currentHltps,
+                                        m_impl->m_currentL1ps,
+                                        m_impl->m_currentBg,
+                                        m_impl->m_ctpConfig,
+                                        m_impl->m_chainList,
+                                        m_impl->m_sequenceList,
+                                        m_impl->m_bgSet, msg() ) );
 
-      // Return gracefully:
-      return StatusCode::SUCCESS;
+         return StatusCode::SUCCESS;
+
+      } else if (m_triggerMenuContainerAvailable) {
+
+         // A little sanity check:
+         if( m_tmc->size() == 0 ) {
+            // This can happen when we encounter empty input files. In which
+            // case we should not bail, but continue, and only bail if by the
+            // start of an event, we still don't see any configurations.
+            ATH_MSG_WARNING( "No trigger configurations are available on "
+                             "the input" );
+            return StatusCode::SUCCESS;
+         }
+
+         m_menu = m_tmc->at( 0 );
+         // Cache the menu's configuration:
+         ATH_CHECK( prepareTriggerMenu( m_menu, m_impl->m_ctpConfig,
+                                        m_impl->m_chainList,
+                                        m_impl->m_sequenceList,
+                                        m_impl->m_bgSet, msg() ) );
+
+         return StatusCode::SUCCESS;
+      }
+
+      ATH_MSG_ERROR( "Both m_menuJSONContainerAvailable and m_triggerMenuContainerAvailable are false");
+      return StatusCode::FAILURE; // Should never get here as checked that one or the other is true above
    }
 
    StatusCode xAODConfigTool::beginEvent() {
@@ -205,14 +383,27 @@ namespace TrigConf {
       // mode at the very beginning of the application. (Depending on the
       // creation order of the objects.) So make sure that we have the
       // configuration objects at hand...
-      if( ( ! m_tmc ) || ( ! m_menu ) ) {
+      if( !m_triggerMenuContainerAvailable and !m_menuJSONContainerAvailable ) {
          ATH_CHECK( beginInputFile() );
       }
 
       // Read the current event's trigger keys:
-      const xAOD::TrigConfKeys* keys = 0;
+      const xAOD::TrigConfKeys* keys = nullptr;
       ATH_CHECK( evtStore()->retrieve( keys, m_eventName ) );
 
+      // Prefer Run 3 data if available
+      if (m_menuJSONContainerAvailable) {
+         return beginEvent_Run3(keys);
+      } else if (m_triggerMenuContainerAvailable) {
+         return beginEvent_Run2(keys);
+      }
+      
+      ATH_MSG_ERROR( "Both m_menuJSONContainerAvailable and m_triggerMenuContainerAvailable are false");
+      return StatusCode::FAILURE;
+
+   }
+
+   StatusCode xAODConfigTool::beginEvent_Run2(const xAOD::TrigConfKeys* keys) {
       // Check if we have the correct menu already:
       if( m_menu && xAODKeysMatch( keys, m_menu ) ) {
          return StatusCode::SUCCESS;
@@ -242,4 +433,98 @@ namespace TrigConf {
       return StatusCode::FAILURE;
    }
 
+   StatusCode xAODConfigTool::beginEvent_Run3(const xAOD::TrigConfKeys* keys) {
+      // Check if we have the correct menu already:
+      bool validConfig = true;
+      if (m_currentHltJson->key() != keys->smk()) {
+         validConfig = false;
+      }
+      if (m_currentL1Json->key() != keys->smk()) {
+         validConfig = false;
+      }
+      if (m_currentHltpsJson->key() != keys->hltpsk()) {
+         validConfig = false;
+      }
+      if (m_currentL1psJson->key() != keys->l1psk()) {
+         validConfig = false;
+      }
+      // if (m_currentBgJson->key() != TODO) {
+      //    validConfig = false;
+      // }
+
+      if (validConfig) {
+         return StatusCode::SUCCESS;
+      }
+
+      // If not, load correct JSON menus from their respective containers, matching against the event's keys ...
+      ATH_CHECK( loadJsonByKey("HLT Menu", m_hltJson, keys->smk(), m_currentHltJson) );
+      ATH_CHECK( loadJsonByKey("L1 Menu", m_l1Json, keys->smk(), m_currentL1Json) );
+      ATH_CHECK( loadJsonByKey("HLT Prescales", m_hltpsJson, keys->hltpsk(), m_currentHltpsJson) );
+      ATH_CHECK( loadJsonByKey("L1 Prescales", m_l1psJson, keys->l1psk(), m_currentL1psJson) );
+      // ATH_CHECK( loadJsonByKey("Bunchgroups", m_bgJson, TODO, m_currentBgJson) );
+
+      // ... and from these serialised JSON strings, populate the ptree data structures...
+      ATH_CHECK( loadPtrees() ); // R3 interfaces now active
+      // ... and finally populate the legacy interface from the ptree data
+      ATH_CHECK( prepareTriggerMenu( m_impl->m_currentHlt,
+                                     m_impl->m_currentL1, 
+                                     m_impl->m_currentHltps,
+                                     m_impl->m_currentL1ps,
+                                     m_impl->m_currentBg,
+                                     m_impl->m_ctpConfig,
+                                     m_impl->m_chainList,
+                                     m_impl->m_sequenceList,
+                                     m_impl->m_bgSet, msg() ) ); // R2 interfaces now active
+
+      return StatusCode::SUCCESS;
+   }
+
+   StatusCode xAODConfigTool::loadJsonByKey(const std::string& humanName, 
+      const xAOD::TriggerMenuJsonContainer* metaContainer, 
+      const uint32_t keyToCheck, 
+      const xAOD::TriggerMenuJson*& ptrToSet)
+   {
+      xAOD::TriggerMenuJsonContainer::const_iterator menu_itr = metaContainer->begin();
+      xAOD::TriggerMenuJsonContainer::const_iterator menu_end = metaContainer->end();
+      for( ; menu_itr != menu_end; ++menu_itr ) {
+         // Check if this is the menu we're looking for:
+         if( keyToCheck != (*menu_itr)->key() ) continue;
+         ptrToSet = *menu_itr;
+         return StatusCode::SUCCESS;
+      }
+
+      ATH_MSG_FATAL("Couldn't find configuration for current event"
+         << ", Requested key=" << keyToCheck
+         << ", Requested menu=" << humanName);
+      return StatusCode::FAILURE;
+   }
+
+   StatusCode xAODConfigTool::loadPtrees() {
+      ATH_CHECK( loadPtree("HLT Menu", m_currentHltJson, m_impl->m_currentHlt) );
+      ATH_CHECK( loadPtree("L1 Menu", m_currentL1Json, m_impl->m_currentL1) );
+      ATH_CHECK( loadPtree("HLT Prescales", m_currentHltpsJson, m_impl->m_currentHltps) );
+      ATH_CHECK( loadPtree("L1 Prescales", m_currentL1psJson, m_impl->m_currentL1ps) );
+      // ATH_CHECK( loadPtree("Bunchgroups", m_currentBgJson, m_impl->m_currentBg) );
+      return StatusCode::SUCCESS;
+   }
+
+   StatusCode xAODConfigTool::loadPtree(const std::string& humanName,
+      const xAOD::TriggerMenuJson* menu,
+      DataStructure& dataStructure)
+   {
+      std::stringstream rawData;
+      rawData << menu->payload();
+      dataStructure.clear();
+      try {
+         boost::property_tree::ptree pt;
+         boost::property_tree::read_json(rawData, pt);
+         dataStructure.setData(std::move(pt));
+      } catch (const boost::property_tree::json_parser_error& e) {
+         ATH_MSG_FATAL("Unable to decode a JSON trigger menu metadata payload for " << humanName << " with key " << menu->key());
+         ATH_MSG_FATAL(e.what());
+         return StatusCode::FAILURE;
+      }
+      return StatusCode::SUCCESS;
+   }
+
 } // namespace TrigConf
diff --git a/Trigger/TrigConfiguration/TrigConfxAOD/TrigConfxAOD/tools/prepareTriggerMenu.h b/Trigger/TrigConfiguration/TrigConfxAOD/TrigConfxAOD/tools/prepareTriggerMenu.h
index 08453573b75a0c47bae3dcd1ef3f0b63b65486ee..a92f2b3be65b5caf5dce2eacff0e599a1a7833f6 100644
--- a/Trigger/TrigConfiguration/TrigConfxAOD/TrigConfxAOD/tools/prepareTriggerMenu.h
+++ b/Trigger/TrigConfiguration/TrigConfxAOD/TrigConfxAOD/tools/prepareTriggerMenu.h
@@ -22,18 +22,34 @@ namespace TrigConf {
    // Forward declaration(s):
    class CTPConfig;
    class HLTChainList;
-  class HLTSequenceList;
+   class HLTSequenceList;
    class BunchGroupSet;
 
+   class HLTMenu;
+   class L1Menu;
+   class HLTPrescalesSet;
+   class L1PrescalesSet;
+   class L1BunchGroupSet;
 
-   /// Function providing translation for the transient configuration
+   /// Function providing translation for the transient configuration from the R2 AOD format
    StatusCode prepareTriggerMenu( const xAOD::TriggerMenu* menu,
                                   CTPConfig& ctpConfig,
                                   HLTChainList& chainList,
-				  HLTSequenceList& sequenceList,
+                                  HLTSequenceList& sequenceList,
                                   BunchGroupSet& bgSet,
                                   MsgStream& msg );
 
+   StatusCode prepareTriggerMenu(const HLTMenu& loadedHlt,
+                                 const L1Menu& loadedL1,
+                                 const HLTPrescalesSet& loadedHltps,
+                                 const L1PrescalesSet& loadedL1ps,
+                                 const L1BunchGroupSet& loadedBgSet,
+                                 CTPConfig& ctpConfig,
+                                 HLTChainList& chainList,
+                                 HLTSequenceList& sequenceList,
+                                 BunchGroupSet& bgSet,
+                                 MsgStream& msg );
+
 } // namespace TrigConf
 
 #endif // TRIGCONFXAOD_TOOLS_PREPARETRIGGERMENU_H
diff --git a/Trigger/TrigConfiguration/TrigConfxAOD/TrigConfxAOD/xAODConfigTool.h b/Trigger/TrigConfiguration/TrigConfxAOD/TrigConfxAOD/xAODConfigTool.h
index dae82ccd6042f8f19890de9b74c335b22b30ec5f..a2727d5b3bc97c6a9701a9ccbd12f77aec434289 100644
--- a/Trigger/TrigConfiguration/TrigConfxAOD/TrigConfxAOD/xAODConfigTool.h
+++ b/Trigger/TrigConfiguration/TrigConfxAOD/TrigConfxAOD/xAODConfigTool.h
@@ -12,16 +12,29 @@
 #include "AsgTools/AsgMetadataTool.h"
 
 // Trigger configuration include(s):
+// Run 2 / legacy structures
 #include "TrigConfInterfaces/ITrigConfigTool.h"
 #include "TrigConfL1Data/CTPConfig.h"
 #include "TrigConfL1Data/BunchGroupSet.h"
 #include "TrigConfHLTData/HLTChainList.h"
 #include "TrigConfHLTData/HLTSequenceList.h"
+// Run 3 structures
+#include "TrigConfData/HLTMenu.h"
+#include "TrigConfData/L1Menu.h"
+#include "TrigConfData/HLTPrescalesSet.h"
+#include "TrigConfData/L1PrescalesSet.h"
+#include "TrigConfData/L1BunchGroupSet.h"
+#include "TrigConfData/DataStructure.h"
 
 // xAOD include(s):
 #include "xAODTrigger/TriggerMenu.h"
 #include "xAODTrigger/TriggerMenuContainer.h"
 
+#include "xAODTrigger/TriggerMenuJson.h"
+#include "xAODTrigger/TriggerMenuJsonContainer.h"
+
+#include "xAODTrigger/TrigConfKeys.h"
+
 namespace TrigConf {
 
    /// Trigger configuration metadata tool for xAOD analysis
@@ -96,6 +109,26 @@ namespace TrigConf {
 
       /// @}
 
+      /// @name Impliment the JSON config interface. TODO - add this to an abstract interface
+      /// @{
+
+      /// Returns the JSON configured HLTMenu ptree
+      const HLTMenu& hltMenu() const;
+
+      /// Returns the JSON configured L1 ptree
+      const L1Menu& l1Menu() const;
+
+      /// Returns the JSON configured HLT prescales ptree
+      const HLTPrescalesSet& hltPrescalesSet() const;
+
+      /// Returns the JSON configured L1 prescales ptree
+      const L1PrescalesSet& l1PrescalesSet() const;
+
+      /// Returns the JSON configured bunchgroup ptree
+      const L1BunchGroupSet& l1BunchGroupSet() const;
+
+      /// @}
+
    protected:
       /// @name Callback function(s) from AsgMetadataTool
       /// @{
@@ -106,18 +139,68 @@ namespace TrigConf {
       /// Function called when a new event is loaded
       virtual StatusCode beginEvent();
 
+      /// Internal call to check / load from a file with Run2 metadata
+      StatusCode beginEvent_Run2(const xAOD::TrigConfKeys* keys);
+
+      /// Internal call to check / load from a file with Run3 metadata
+      StatusCode beginEvent_Run3(const xAOD::TrigConfKeys* keys);
+
       /// @}
 
    private:
+
+      /// @name Run 3 helper functions
+      /// @{
+
+      /// Locates a Run3 TriggerMenuJson object inside a container by key. Loads it into the m_currentXXXJson ptr
+      StatusCode loadJsonByKey(const std::string& humanName, 
+         const xAOD::TriggerMenuJsonContainer* metaContainer, 
+         const uint32_t keyToCheck, 
+         const xAOD::TriggerMenuJson*& ptrToSet);
+
+      /// Load all m_currentXXXJson serialised JSON data into ptrees inside m_impl
+      StatusCode loadPtrees();
+
+      /// Load single m_currentXXXJson serialised JSON data into ptree
+      StatusCode loadPtree(const std::string& humanName,
+         const xAOD::TriggerMenuJson* menu,
+         DataStructure& dataStructure);
+
+      /// @}
+
       /// Key for the event-level configuration identifier object
       std::string m_eventName;
-      /// Key for the trigger configuration metadata object
-      std::string m_metaName;
-
-      /// The configuration object of the current input file
+      /// Key for the trigger configuration metadata object (Run 2)
+      std::string m_metaName_run2;
+      /// Key for the trigger configuration metadata objects (Run 3)
+      std::string m_metaNameJSON_hlt;
+      std::string m_metaNameJSON_l1;
+      std::string m_metaNameJSON_hltps;
+      std::string m_metaNameJSON_l1ps;
+      std::string m_metaNameJSON_bg;
+
+      /// The configuration object of the current input file (for Run2 AOD)
       const xAOD::TriggerMenuContainer* m_tmc;
-      /// The active configuration for the current event
+      /// The configuration object of the current input file (for Run3 AOD)
+      const xAOD::TriggerMenuJsonContainer* m_hltJson;
+      const xAOD::TriggerMenuJsonContainer* m_l1Json;
+      const xAOD::TriggerMenuJsonContainer* m_hltpsJson;
+      const xAOD::TriggerMenuJsonContainer* m_l1psJson;
+      const xAOD::TriggerMenuJsonContainer* m_bgJson;
+
+      /// The active configuration for the current event (For Run2 AOD)
       const xAOD::TriggerMenu* m_menu;
+      /// The active configuration for the current event (For Run3 AOD)
+      const xAOD::TriggerMenuJson* m_currentHltJson;
+      const xAOD::TriggerMenuJson* m_currentL1Json;
+      const xAOD::TriggerMenuJson* m_currentHltpsJson;
+      const xAOD::TriggerMenuJson* m_currentL1psJson;
+      const xAOD::TriggerMenuJson* m_currentBgJson;
+
+      /// Is decoded R2 format data available?
+      bool m_triggerMenuContainerAvailable;
+      /// Is decoded R3 format data available?
+      bool m_menuJSONContainerAvailable;
 
       // A few members moved to an impl class to hide them from cling.
       // Otherwise, we get warnings about the use of boost::multi_index
diff --git a/Trigger/TrigConfiguration/TrigConfxAOD/src/xAODConfigSvc.cxx b/Trigger/TrigConfiguration/TrigConfxAOD/src/xAODConfigSvc.cxx
index 819164ebbbaae344b5348712eb5089bd1bd6d9ac..5ecb14cd5089cbe8f8df3f9b06543ed14757d77b 100644
--- a/Trigger/TrigConfiguration/TrigConfxAOD/src/xAODConfigSvc.cxx
+++ b/Trigger/TrigConfiguration/TrigConfxAOD/src/xAODConfigSvc.cxx
@@ -19,6 +19,10 @@
 #include "TrigConfxAOD/tools/prepareTriggerMenu.h"
 #include "TrigConfxAOD/tools/xAODKeysMatch.h"
 
+// Boost includes
+#include <boost/property_tree/ptree.hpp>
+#include <boost/property_tree/json_parser.hpp>
+
 namespace TrigConf {
 
    xAODConfigSvc::xAODConfigSvc( const std::string& name, ISvcLocator* svcLoc )
@@ -26,7 +30,9 @@ namespace TrigConf {
         m_stopOnFailure( true ), m_isInFailure( false ),
         m_tmcAux( nullptr ), m_tmc( nullptr ), m_menu(),
         m_ctpConfig(), m_chainList(), m_sequenceList(), m_bgSet(),
-        m_metaStore( "InputMetaDataStore", name ) {
+        m_metaStore( "InputMetaDataStore", name ),
+        m_triggerMenuContainerAvailable( false ),
+        m_menuJSONContainerAvailable( false ) {
 
    }
 
@@ -49,10 +55,32 @@ namespace TrigConf {
       incSvc->addListener( this, IncidentType::BeginInputFile, 0,
                            m_stopOnFailure );
 
+      // Internal holder for R2 payloads
       m_tmcAux = std::make_unique<xAOD::TriggerMenuAuxContainer>();
       m_tmc    = std::make_unique<xAOD::TriggerMenuContainer>();
       m_tmc->setStore( m_tmcAux.get() );
 
+      // Internal holders for R3 payloads
+      m_hltJsonAux = std::make_unique<xAOD::TriggerMenuJsonAuxContainer>();
+      m_hltJson    = std::make_unique<xAOD::TriggerMenuJsonContainer>();
+      m_hltJson->setStore( m_hltJsonAux.get() );
+
+      m_l1JsonAux = std::make_unique<xAOD::TriggerMenuJsonAuxContainer>();
+      m_l1Json    = std::make_unique<xAOD::TriggerMenuJsonContainer>();
+      m_l1Json->setStore( m_l1JsonAux.get() );
+
+      m_hltpsJsonAux = std::make_unique<xAOD::TriggerMenuJsonAuxContainer>();
+      m_hltpsJson    = std::make_unique<xAOD::TriggerMenuJsonContainer>();
+      m_hltpsJson->setStore( m_hltpsJsonAux.get() );
+
+      m_l1psJsonAux = std::make_unique<xAOD::TriggerMenuJsonAuxContainer>();
+      m_l1psJson    = std::make_unique<xAOD::TriggerMenuJsonContainer>();
+      m_l1psJson->setStore( m_l1psJsonAux.get() );
+
+      m_bgJsonAux = std::make_unique<xAOD::TriggerMenuJsonAuxContainer>();
+      m_bgJson    = std::make_unique<xAOD::TriggerMenuJsonContainer>();
+      m_bgJson->setStore( m_bgJsonAux.get() );
+
       // Reset the internal flag:
       m_isInFailure = false;
 
@@ -97,19 +125,25 @@ namespace TrigConf {
    }
 
    uint32_t xAODConfigSvc::lvl1PrescaleKey() const {
+      if (m_menuJSONContainerAvailable) {
 
-      // Check that we know the configuration already:
-      if( ! m_menu.get()->m_ptr ) {
-         REPORT_MESSAGE( MSG::ERROR )
-            << "Trigger menu not yet known. Configuration key not returned.";
-         throw GaudiException( "Service not initialised correctly",
-                               "TrigConf::xAODConfigSvc::lvl1PrescaleKey",
-                               StatusCode::FAILURE );
-         return 0;
-      }
+         return m_currentL1psJson.get()->m_ptr->key();
 
-      // Return the key from the slot-specific metadata object:
-      return m_menu.get()->m_ptr->l1psk();
+      } else {
+
+         // Check that we know the configuration already:
+         if( ! m_menu.get()->m_ptr ) {
+            REPORT_MESSAGE( MSG::ERROR )
+               << "Trigger menu not yet known. Configuration key not returned.";
+            throw GaudiException( "Service not initialised correctly",
+                                  "TrigConf::xAODConfigSvc::lvl1PrescaleKey",
+                                  StatusCode::FAILURE );
+            return 0;
+         }
+
+         // Return the key from the slot-specific metadata object:
+         return m_menu.get()->m_ptr->l1psk();
+      }
    }
 
    const HLTChainList* xAODConfigSvc::chainList() const {
@@ -173,35 +207,99 @@ namespace TrigConf {
    }
 
    uint32_t xAODConfigSvc::masterKey() const {
+      if (m_menuJSONContainerAvailable) {
 
-      // Check that we know the configuration already:
-      if( ! m_menu.get()->m_ptr ) {
-         REPORT_MESSAGE( MSG::FATAL )
-            << "Trigger menu not yet known. Configuration key not returned.";
+         return m_currentHltJson.get()->m_ptr->key();
+
+      } else {
+
+         // Check that we know the configuration already:
+         if( ! m_menu.get()->m_ptr ) {
+            REPORT_MESSAGE( MSG::FATAL )
+               << "Trigger menu not yet known. Configuration key not returned.";
+            throw GaudiException( "Service not initialised correctly",
+                                  "TrigConf::xAODConfigSvc::masterKey",
+                                  StatusCode::FAILURE );
+            return 0;
+         }
+
+         // Return the key from the slot-specific metadata object:
+         return m_menu.get()->m_ptr->smk();
+
+      }
+   }
+
+   uint32_t xAODConfigSvc::hltPrescaleKey() const {
+      if (m_menuJSONContainerAvailable) {
+
+         return m_currentHltpsJson.get()->m_ptr->key();
+
+      } else {
+
+         // Check that we know the configuration already:
+         if( ! m_menu.get()->m_ptr ) {
+            REPORT_MESSAGE( MSG::FATAL )
+               << "Trigger menu not yet known. Configuration key not returned.";
+            throw GaudiException( "Service not initialised correctly",
+                                  "TrigConf::xAODConfigSvc::hltPrescaleKey",
+                                  StatusCode::FAILURE );
+            return 0;
+         }
+
+         // Return the key from the slot-specific metadata object:
+         return m_menu.get()->m_ptr->hltpsk();
+
+      }
+   }
+
+   const HLTMenu& xAODConfigSvc::hltMenu(const EventContext& ctx) const {
+      if (!m_menuJSONContainerAvailable) {
+         REPORT_MESSAGE( MSG::FATAL ) << "Run 3 hltMenu JSON not loaded." << endmsg;
          throw GaudiException( "Service not initialised correctly",
-                               "TrigConf::xAODConfigSvc::masterKey",
+                               "TrigConf::xAODConfigSvc::hltMenu",
                                StatusCode::FAILURE );
-         return 0;
       }
+      return *(m_currentHlt.get(ctx));
+   }
 
-      // Return the key from the slot-specific metadata object:
-      return m_menu.get()->m_ptr->smk();
+   const L1Menu& xAODConfigSvc::l1Menu(const EventContext& ctx) const {
+      if (!m_menuJSONContainerAvailable) {
+         REPORT_MESSAGE( MSG::FATAL ) << "Run 3 l1Menu JSON not loaded." << endmsg;
+         throw GaudiException( "Service not initialised correctly",
+                               "TrigConf::xAODConfigSvc::l1Menu",
+                               StatusCode::FAILURE );
+      }
+      return *(m_currentL1.get(ctx));
    }
 
-   uint32_t xAODConfigSvc::hltPrescaleKey() const {
+   const HLTPrescalesSet& xAODConfigSvc::hltPrescalesSet(const EventContext& ctx) const {
+      if (!m_menuJSONContainerAvailable) {
+         REPORT_MESSAGE( MSG::FATAL ) << "Run 3 hltPrescalesSet JSON not loaded." << endmsg;
+         throw GaudiException( "Service not initialised correctly",
+                               "TrigConf::xAODConfigSvc::hltPrescalesSet",
+                               StatusCode::FAILURE );
+      }
+      return *(m_currentHltps.get(ctx));
+   }
 
-      // Check that we know the configuration already:
-      if( ! m_menu.get()->m_ptr ) {
-         REPORT_MESSAGE( MSG::FATAL )
-            << "Trigger menu not yet known. Configuration key not returned.";
+   const L1PrescalesSet& xAODConfigSvc::l1PrescalesSet(const EventContext& ctx) const {
+      if (!m_menuJSONContainerAvailable) {
+         REPORT_MESSAGE( MSG::FATAL ) << "Run 3 l1PrescalesSet JSON not loaded." << endmsg;
          throw GaudiException( "Service not initialised correctly",
-                               "TrigConf::xAODConfigSvc::hltPrescaleKey",
+                               "TrigConf::xAODConfigSvc::l1PrescalesSet",
                                StatusCode::FAILURE );
-         return 0;
       }
+      return *(m_currentL1ps.get(ctx));
+   }
 
-      // Return the key from the slot-specific metadata object:
-      return m_menu.get()->m_ptr->hltpsk();
+   const L1BunchGroupSet& xAODConfigSvc::l1BunchGroupSet(const EventContext& ctx) const {
+      if (!m_menuJSONContainerAvailable) {
+         REPORT_MESSAGE( MSG::FATAL ) << "Run 3 l1BunchGroupSet JSON not loaded." << endmsg;
+         throw GaudiException( "Service not initialised correctly",
+                               "TrigConf::xAODConfigSvc::l1BunchGroupSet",
+                               StatusCode::FAILURE );
+      }
+      return *(m_currentBg.get(ctx));
    }
 
    StatusCode xAODConfigSvc::queryInterface( const InterfaceID& riid,
@@ -288,41 +386,149 @@ namespace TrigConf {
 
    StatusCode xAODConfigSvc::readMetadata() {
 
-      // Read the metadata object...
-      const xAOD::TriggerMenuContainer* input = nullptr;
-      if( m_metaStore->retrieve( input, m_metaName ).isFailure() ) {
+      // Only one thread at a time is allowed to process a new file being opened
+      // and this should only happen when it is not being iterated over
+      // as part of the BeginEvent incident.
+      std::unique_lock lockUnique(m_sharedMutex);
+
+      m_triggerMenuContainerAvailable = true;
+      m_menuJSONContainerAvailable = true;
+
+      // Read the R2 metadata object...
+      const xAOD::TriggerMenuContainer* input_tmc = nullptr;
+      if( m_metaStore->retrieve( input_tmc, m_metaName ).isFailure() ) {
+         m_triggerMenuContainerAvailable = false;
+      }
+
+      // Read the R3 metadata object...
+      const xAOD::TriggerMenuJsonContainer* input_hlt = nullptr;
+      const xAOD::TriggerMenuJsonContainer* input_l1 = nullptr;
+      const xAOD::TriggerMenuJsonContainer* input_hltps = nullptr;
+      const xAOD::TriggerMenuJsonContainer* input_l1ps = nullptr;
+      // const xAOD::TriggerMenuJsonContainer* input_bg = nullptr;
+      if( m_metaStore->retrieve( input_hlt, m_metaNameJSON_hlt ).isFailure() ) {
+         m_menuJSONContainerAvailable = false;
+      }
+      if( m_metaStore->retrieve( input_l1, m_metaNameJSON_l1 ).isFailure() ) {
+         m_menuJSONContainerAvailable = false;
+      }
+      if( m_metaStore->retrieve( input_hltps, m_metaNameJSON_hltps ).isFailure() ) {
+         m_menuJSONContainerAvailable = false;
+      }
+      if( m_metaStore->retrieve( input_l1ps, m_metaNameJSON_l1ps ).isFailure() ) {
+         m_menuJSONContainerAvailable = false;
+      }
+      // if( m_metaStore->retrieve( input_bg, m_metaNameJSON_bg ).isFailure() ) {
+      //    m_menuJSONContainerAvailable = false;
+      // }
+
+      if (!m_triggerMenuContainerAvailable && !m_menuJSONContainerAvailable) {
          // Update the internal flag:
          m_isInFailure = true;
          // Decide what to do:
          if( m_stopOnFailure ) {
-            REPORT_MESSAGE( MSG::FATAL )
-               << "Couldn't retrieve xAOD::TriggerMenuContainer";
+            REPORT_MESSAGE( MSG::FATAL ) << "Couldn't retrieve xAOD::TriggerMenuContainer or xAOD::TriggerMenuJsonContainer(s)" << endmsg;
             return StatusCode::FAILURE;
          } else {
-            REPORT_MESSAGE( MSG::INFO ) << "Couldn't retrieve xAOD::TriggerMenuContainer" << endmsg;
+            REPORT_MESSAGE( MSG::WARNING ) << "Couldn't retrieve xAOD::TriggerMenuContainer or xAOD::TriggerMenuJsonContainer(s)" << endmsg;
+            return StatusCode::SUCCESS;
+         }
+      }
+
+      // From file #2 and onwards, check for mixed-messages from the input files.
+      // Note from the check just above, we know that we have at least one type of data available on this input file
+      //
+      // We do this as we currently have just two "available" flags, for the two data formats. Not two per slot
+      if (m_tmc->size() > 0 && !m_triggerMenuContainerAvailable && m_menuJSONContainerAvailable) {
+         m_isInFailure = true;
+         m_triggerMenuContainerAvailable = false;
+         m_menuJSONContainerAvailable = false;
+         if( m_stopOnFailure ) {
+            REPORT_MESSAGE( MSG::FATAL )
+               << "In this input file we found xAOD::TriggerMenuJsonContainer(s), but no xAOD::TriggerMenuContainer. "
+               << "This is inconsistent with previous input files." << endmsg;            
+               return StatusCode::FAILURE;
+         } else {
+            REPORT_MESSAGE( MSG::WARNING ) 
+               << "In this input file we found xAOD::TriggerMenuJsonContainer(s), but no xAOD::TriggerMenuContainer. "
+               << "This is inconsistent with previous input files." << endmsg;         
+            return StatusCode::SUCCESS;
+         }
+      }
+      if (m_hltJson->size() > 0 && !m_menuJSONContainerAvailable && m_triggerMenuContainerAvailable) {
+         m_isInFailure = true;
+         m_triggerMenuContainerAvailable = false;
+         m_menuJSONContainerAvailable = false;
+         if( m_stopOnFailure ) {
+            REPORT_MESSAGE( MSG::FATAL )
+               << "In this input file we found xAOD::TriggerMenuContainer, but no xAOD::TriggerMenuJsonContainer. "
+               << "This is inconsistent with previous input files." << endmsg;            
+               return StatusCode::FAILURE;
+         } else {
+            REPORT_MESSAGE( MSG::WARNING ) 
+               << "In this input file we found xAOD::TriggerMenuContainer, but no xAOD::TriggerMenuJsonContainer. "
+               << "This is inconsistent with previous input files." << endmsg;        
             return StatusCode::SUCCESS;
          }
       }
 
       // Let the user know what happened:
-      REPORT_MESSAGE( MSG::DEBUG ) << "Loaded trigger configuration metadata container"  << endmsg;
+      REPORT_MESSAGE( MSG::DEBUG ) << "Loaded trigger configuration metadata container(s)"  << endmsg;
+
+      // If available, give preference to the R3 format
+      if (m_menuJSONContainerAvailable) {
+
+         copyMetadataToPersonalStore(input_hlt, m_hltJson.get());
+         copyMetadataToPersonalStore(input_l1, m_l1Json.get());
+         copyMetadataToPersonalStore(input_hltps, m_hltpsJson.get());
+         copyMetadataToPersonalStore(input_l1ps, m_l1psJson.get());
+         // copyMetadataToPersonalStore(input_bg, m_bgJson.get());
 
-      // A little sanity check:
-      if( ! input->size() ) {
-         REPORT_MESSAGE( MSG::WARNING ) << "No trigger configurations are available on the input" << endmsg;
          return StatusCode::SUCCESS;
-      }
 
-      // Only one thread at a time is allowed to extend m_tmc, 
-      // and this should only happen when it is not being iterated over
-      // as part of the BeginEvent indicent.
-      std::unique_lock lockUnique(m_sharedMutex);
+      } else if (m_triggerMenuContainerAvailable) { // Otherwise load the Run 2 format
+
+         // A little sanity check:
+         if( ! input_tmc->size() ) {
+            REPORT_MESSAGE( MSG::WARNING ) << "No trigger configurations are available on the input" << endmsg;
+            return StatusCode::SUCCESS;
+         }
+
+         // Copy in new menus
+         for ( const xAOD::TriggerMenu* inputMenu : *input_tmc ) {
+            bool alreadyHave = false;
+            for( const xAOD::TriggerMenu* existingMenu : *m_tmc ) {
+               if (xAODKeysMatch(inputMenu, existingMenu)) {
+                  alreadyHave = true;
+                  break;
+               }
+            }
+            if (alreadyHave) {
+               continue;
+            }
+            // Copy this menu into the service's internal cache of all menus
+            xAOD::TriggerMenu* newMenu = new xAOD::TriggerMenu();
+            m_tmc->push_back( newMenu ); // Note: 'newMenu' is now memory managed by m_tmc
+            *newMenu = *inputMenu;
+            REPORT_MESSAGE( MSG::DEBUG ) << "Imported new configuration: SMK = " << newMenu->smk()
+               << ", L1PSK = " << newMenu->l1psk()
+               << ", HLTPSK = " << newMenu->hltpsk() << endmsg;
+         }
 
-      // Copy in new menus
-      for ( const xAOD::TriggerMenu* inputMenu : *input ) {
+         return StatusCode::SUCCESS;
+
+      } // m_menuJSONContainerAvailable or m_triggerMenuContainerAvailable
+
+      //Should never get here (due to check above)
+      ATH_MSG_ERROR( "Both m_menuJSONContainerAvailable and m_triggerMenuContainerAvailable are false" );
+      return StatusCode::FAILURE;
+   }
+
+   void xAODConfigSvc::copyMetadataToPersonalStore(const xAOD::TriggerMenuJsonContainer* input, xAOD::TriggerMenuJsonContainer* existing) {
+      for ( const xAOD::TriggerMenuJson* inputTriggerMenuJson : *input ) {
          bool alreadyHave = false;
-         for( const xAOD::TriggerMenu* existingMenu : *m_tmc ) {
-            if (xAODKeysMatch(inputMenu, existingMenu)) {
+         for( const xAOD::TriggerMenuJson* existingTriggerMenuJson : *existing ) {
+            if (inputTriggerMenuJson->key() == existingTriggerMenuJson->key()) {
                alreadyHave = true;
                break;
             }
@@ -330,17 +536,12 @@ namespace TrigConf {
          if (alreadyHave) {
             continue;
          }
-         // Copy this menu into the service's internal cache of all menus
-         xAOD::TriggerMenu* newMenu = new xAOD::TriggerMenu();
-         m_tmc->push_back( newMenu ); // Note: 'newMenu' is now memory managed by m_tmc
-         *newMenu = *inputMenu;
-         REPORT_MESSAGE( MSG::DEBUG ) << "Imported new configuration: SMK = " << newMenu->smk()
-            << ", L1PSK = " << newMenu->l1psk()
-            << ", HLTPSK = " << newMenu->hltpsk() << endmsg;
+         // Copy this menu JSON into the service's internal cache of all menus
+         xAOD::TriggerMenuJson* newTriggerMenuJson = new xAOD::TriggerMenuJson();
+         existing->push_back( newTriggerMenuJson ); // Note: 'newTriggerMenuJson' is now memory managed by 'existing'
+         *newTriggerMenuJson = *inputTriggerMenuJson; // Perform xAOD copy
+         REPORT_MESSAGE( MSG::DEBUG ) << "Imported new configuration: Name = " << newTriggerMenuJson->name() << " Key = " << newTriggerMenuJson->key() << endmsg;
       }
-
-      // Return gracefully:
-      return StatusCode::SUCCESS;
    }
 
    StatusCode xAODConfigSvc::prepareEvent() {
@@ -364,10 +565,20 @@ namespace TrigConf {
          }
       }
 
+      if (m_menuJSONContainerAvailable) { // Run 3 AOD decoding mode
+         return prepareEventxAODTriggerMenuJson(keys.cptr(), context);
+      } else if (m_triggerMenuContainerAvailable) {  // Run 2 AOD decoding mode
+         return prepareEventxAODTriggerMenu(keys.cptr(), context);
+      }
+      ATH_MSG_ERROR( "Both m_menuJSONContainerAvailable and m_triggerMenuContainerAvailable are false" );
+      return StatusCode::FAILURE;
+   }
+
+   StatusCode xAODConfigSvc::prepareEventxAODTriggerMenu(const xAOD::TrigConfKeys* keys, const EventContext& context) {
       const xAOD::TriggerMenu* loadedMenuInSlot = m_menu.get(context)->m_ptr;
 
       // Check if we have the correct menu already:
-      if( loadedMenuInSlot != nullptr && xAODKeysMatch( keys.cptr(), loadedMenuInSlot ) ) {
+      if( loadedMenuInSlot != nullptr && xAODKeysMatch( keys, loadedMenuInSlot ) ) {
          return StatusCode::SUCCESS;
       }
 
@@ -380,7 +591,7 @@ namespace TrigConf {
       xAOD::TriggerMenuContainer::const_iterator menu_end = m_tmc->end();
       for( ; menu_itr != menu_end; ++menu_itr ) {
          // Check if this is the menu we're looking for:
-         if( ! xAODKeysMatch( keys.cptr(), *menu_itr ) ) continue;
+         if( ! xAODKeysMatch( keys, *menu_itr ) ) continue;
          // Remember it's pointer:
          loadedMenuInSlot = *menu_itr;
          m_menu.get(context)->m_ptr = loadedMenuInSlot;
@@ -408,4 +619,127 @@ namespace TrigConf {
       return StatusCode::FAILURE;
    }
 
+
+
+
+   StatusCode xAODConfigSvc::prepareEventxAODTriggerMenuJson(const xAOD::TrigConfKeys* keys, const EventContext& context) {
+      const xAOD::TriggerMenuJson* loadedHltJson = m_currentHltJson.get(context)->m_ptr;
+      const xAOD::TriggerMenuJson* loadedL1Json = m_currentL1Json.get(context)->m_ptr;
+      const xAOD::TriggerMenuJson* loadedHltpsJson = m_currentHltpsJson.get(context)->m_ptr;
+      const xAOD::TriggerMenuJson* loadedL1psJson = m_currentL1psJson.get(context)->m_ptr;
+      //const xAOD::TriggerMenuJson* loadedBgJson = m_currentBgJson.get(context)->m_ptr;
+
+      bool validConfig = true;
+      if (loadedHltJson == nullptr || loadedHltJson->key() != keys->smk()) {
+         validConfig = false;
+      }
+      if (loadedL1Json == nullptr || loadedL1Json->key() != keys->smk()) {
+         validConfig = false;
+      }
+      if (loadedHltpsJson == nullptr || loadedHltpsJson->key() != keys->hltpsk()) {
+         validConfig = false;
+      }
+      if (loadedL1psJson == nullptr || loadedL1psJson->key() != keys->l1psk()) {
+         validConfig = false;
+      }
+      // if (loadedBgJson == nullptr || loadedBgJson->key() != TODO) {
+      //    validConfig = false;
+      // }
+
+      if (validConfig) {
+         return StatusCode::SUCCESS;
+      }
+
+      // If not, let's look for the correct configuration:
+      // Open a shared lock. OK for multiple events to search at the same time,
+      // but prevent the extension of m_hltJson et. al. from a BeginInputFile incident.  
+      std::shared_lock lockShared(m_sharedMutex);
+
+      TriggerMenuJsonPtrWrapper& currentHltJson   = *(m_currentHltJson.get(context));
+      TriggerMenuJsonPtrWrapper& currentL1Json    = *(m_currentL1Json.get(context));
+      TriggerMenuJsonPtrWrapper& currentHltpsJson = *(m_currentHltpsJson.get(context));
+      TriggerMenuJsonPtrWrapper& currentL1psJson  = *(m_currentL1psJson.get(context));
+      //TriggerMenuJsonPtrWrapper& currentBgJson    = *(m_currentBgJson.get(context));
+
+      TrigConf::HLTMenu&         currentHlt   = *(m_currentHlt.get(context));
+      TrigConf::L1Menu&          currentL1    = *(m_currentL1.get(context));
+      TrigConf::HLTPrescalesSet& currentHltps = *(m_currentHltps.get(context));
+      TrigConf::L1PrescalesSet&  currentL1ps  = *(m_currentL1ps.get(context));
+      TrigConf::L1BunchGroupSet& currentBg    = *(m_currentBg.get(context));
+
+      ATH_CHECK( loadPtree("HLT Menu",      m_hltJson.get(),   keys->smk(),    currentHltJson,   currentHlt) );
+      ATH_CHECK( loadPtree("L1 Menu",       m_l1Json.get(),    keys->smk(),    currentL1Json,    currentL1) );
+      ATH_CHECK( loadPtree("HLT Prescales", m_hltpsJson.get(), keys->hltpsk(), currentHltpsJson, currentHltps) );
+      ATH_CHECK( loadPtree("L1 Prescales",  m_l1psJson.get(),  keys->l1psk(),  currentL1psJson,  currentL1ps) );
+      // ATH_CHECK( loadPtree("Bunchgroups",   m_bgJson.get(),    TODO,           currentBgGJson,    currentBg) );
+   
+      CTPConfig& ctpConfig = *(m_ctpConfig.get(context));
+      HLTChainList& chainList = *(m_chainList.get(context));
+      HLTSequenceList& sequenceList = *(m_sequenceList.get(context));
+      BunchGroupSet& bgSet = *(m_bgSet.get(context));
+
+      CHECK( prepareTriggerMenu( currentHlt,
+                                 currentL1,
+                                 currentHltps,
+                                 currentL1ps,
+                                 currentBg,
+                                 ctpConfig, 
+                                 chainList,
+                                 sequenceList,
+                                 bgSet,
+                                 msg() ) );
+
+      REPORT_MESSAGE( MSG::INFO ) << "Loaded xAOD::TriggerMenuJson configuration:"
+          << "  SMK = " << keys->smk()
+          << ", L1PSK = " << keys->l1psk()
+          << ", HLTPSK = " << keys->hltpsk() << endmsg;
+
+      REPORT_MESSAGE( MSG::DEBUG ) << "ctpConfig.menu().size() = " << ctpConfig.menu().size()
+         << " chainList.size() = " << chainList.size()
+         << " sequenceList.size() = " << sequenceList.size()
+         << " bgSet.bunchGroups().size() = " << bgSet.bunchGroups().size() << endmsg;
+
+      return StatusCode::SUCCESS;
+
+   }
+
+   StatusCode xAODConfigSvc::loadPtree(const std::string& humanName, 
+                                       const xAOD::TriggerMenuJsonContainer* metaContainer, 
+                                       const uint32_t keyToCheck,
+                                       TriggerMenuJsonPtrWrapper& cacheOfLoadedMenuPtr,
+                                       DataStructure& dataStructure) {
+      xAOD::TriggerMenuJsonContainer::const_iterator menu_itr = metaContainer->begin();
+      xAOD::TriggerMenuJsonContainer::const_iterator menu_end = metaContainer->end();
+      const xAOD::TriggerMenuJson* ptrToLocatedMenu = nullptr;
+      for( ; menu_itr != menu_end; ++menu_itr ) {
+         // Check if this is the menu we're looking for:
+         if( keyToCheck != (*menu_itr)->key() ) continue;
+         // Remember its pointer:
+         ptrToLocatedMenu = *menu_itr;
+         cacheOfLoadedMenuPtr.m_ptr = ptrToLocatedMenu;
+         std::stringstream rawData;
+         rawData << ptrToLocatedMenu->payload();
+         dataStructure.clear();
+         try {
+            boost::property_tree::ptree pt;
+            boost::property_tree::read_json(rawData, pt);
+            dataStructure.setData(std::move(pt));
+         } catch (const boost::property_tree::json_parser_error& e) {
+            REPORT_MESSAGE( MSG::FATAL ) << "Unable to decode a JSON trigger menu metadata payload for " << humanName << " with key " << keyToCheck << endmsg;
+            REPORT_MESSAGE( MSG::FATAL ) << e.what();
+            return StatusCode::FAILURE;
+         }
+      }
+
+      if (ptrToLocatedMenu == nullptr) {
+         REPORT_MESSAGE( MSG::FATAL )
+            << "Couldn't find configuration for current event"
+            << ", Requested key=" << keyToCheck
+            << ", Requested menu=" << humanName
+            << endmsg;
+         return StatusCode::FAILURE;
+      }
+      return StatusCode::SUCCESS;
+   }
+
 } // namespace TrigConf
diff --git a/Trigger/TrigConfiguration/TrigConfxAOD/src/xAODConfigSvc.h b/Trigger/TrigConfiguration/TrigConfxAOD/src/xAODConfigSvc.h
index 3b359a7b399fa77c05710b46176f9c60a4e2d38d..5d23c7801c8cf3fd71902eb1b3d8032861e8841a 100644
--- a/Trigger/TrigConfiguration/TrigConfxAOD/src/xAODConfigSvc.h
+++ b/Trigger/TrigConfiguration/TrigConfxAOD/src/xAODConfigSvc.h
@@ -22,10 +22,19 @@
 #include "TrigConfHLTData/HLTChainList.h"
 #include "TrigConfHLTData/HLTSequenceList.h"
 
+#include "TrigConfData/HLTMenu.h"
+#include "TrigConfData/L1Menu.h"
+#include "TrigConfData/HLTPrescalesSet.h"
+#include "TrigConfData/L1PrescalesSet.h"
+#include "TrigConfData/L1BunchGroupSet.h"
+
 // xAOD include(s):
 #include "xAODTrigger/TriggerMenu.h"
 #include "xAODTrigger/TriggerMenuContainer.h"
 #include "xAODTrigger/TriggerMenuAuxContainer.h"
+#include "xAODTrigger/TriggerMenuJson.h"
+#include "xAODTrigger/TriggerMenuJsonContainer.h"
+#include "xAODTrigger/TriggerMenuJsonAuxContainer.h"
 #include "xAODTrigger/TrigConfKeys.h"
 
 #include <shared_mutex>
@@ -45,6 +54,14 @@ namespace TrigConf {
       const xAOD::TriggerMenu* m_ptr;
    };
 
+   /**
+    *  @short Small utility class to wrap a pointer to a const xAOD::TriggerMenuJson
+    */
+   struct TriggerMenuJsonPtrWrapper {
+      TriggerMenuJsonPtrWrapper() : m_ptr(nullptr) {}
+      const xAOD::TriggerMenuJson* m_ptr;
+   };
+
    /**
     *  @short Trigger configuration service used when reading an xAOD file
     *
@@ -145,6 +162,26 @@ namespace TrigConf {
 
       /// @}
 
+      /// @name Impliment the JSON config interface. TODO - add this to an abstract interface
+      /// @{
+
+      /// Returns the JSON configured HLTMenu ptree
+      const HLTMenu& hltMenu(const EventContext& ctx) const;
+
+      /// Returns the JSON configured L1 ptree
+      const L1Menu& l1Menu(const EventContext& ctx) const;
+
+      /// Returns the JSON configured HLT prescales ptree
+      const HLTPrescalesSet& hltPrescalesSet(const EventContext& ctx) const;
+
+      /// Returns the JSON configured L1 prescales ptree
+      const L1PrescalesSet& l1PrescalesSet(const EventContext& ctx) const;
+
+      /// Returns the JSON configured bunchgroup ptree
+      const L1BunchGroupSet& l1BunchGroupSet(const EventContext& ctx) const;
+
+      /// @}
+
       /// Function describing to Gaudi the interface(s) implemented
       virtual StatusCode queryInterface( const InterfaceID& riid,
                                          void** ppvIf ) override;
@@ -162,27 +199,104 @@ namespace TrigConf {
       /// Function setting up the service for a new event
       StatusCode prepareEvent();
 
+      /// Helper function for copying into the service's private data store
+      void copyMetadataToPersonalStore(const xAOD::TriggerMenuJsonContainer* input, xAOD::TriggerMenuJsonContainer* existing);
+
+      /// Do per-event decoding for R3 serialised xAOD::TriggerMenuJson metadata
+      StatusCode prepareEventxAODTriggerMenuJson(const xAOD::TrigConfKeys* keys, const EventContext& context);
+
+      /// Do per-event decoding for R2 serliased xAOD::TriggerMenu metadata 
+      StatusCode prepareEventxAODTriggerMenu(const xAOD::TrigConfKeys* keys, const EventContext& context);
+
+      /// Helper function to find a JSON in a given TriggerMenuJsonContainer using a given key, extract its ptree data
+      /// @param humanName Name to print if things go wrong
+      /// @param metaContainer Metadata container of TriggerMenuJson objects from which to load a ptree
+      /// @param keyToCheck The key of the ptree to load
+      /// @param cacheOfLoadedMenuPtr Slot's cache of the currently loaded TriggerMenuJson
+      /// @param DataStructure dataStructure object to fill with the TriggerMenuJson's payload
+      StatusCode loadPtree(const std::string& humanName, 
+                           const xAOD::TriggerMenuJsonContainer* metaContainer, 
+                           const uint32_t keyToCheck,
+                           TriggerMenuJsonPtrWrapper& cacheOfLoadedMenuPtr,
+                           DataStructure& dataStructure);
 
       SG::ReadHandleKey<xAOD::TrigConfKeys> m_eventKey{this, "EventObjectName", "TrigConfKeys", 
         "Key for the event-level configuration identifier object"};
+
+      /// @name Names for reading the R2 (and R1) AOD metadata payload
+      /// @{
       Gaudi::Property<std::string> m_metaName{this, "MetaObjectName", "TriggerMenu", 
         "Key for the trigger configuration metadata object"};
+      /// @}
+
+      /// @name Names for reading the R3 AOD metadata payload
+      /// @{
+      Gaudi::Property< std::string > m_metaNameJSON_hlt {this, "JSONMetaObjectNameHLT", "TriggerMenuJson_HLT",
+        "StoreGate key for the xAOD::TriggerMenuJson HLT configuration object"};
+
+      Gaudi::Property< std::string > m_metaNameJSON_l1 {this, "JSONMetaObjectNameL1", "TriggerMenuJson_L1",
+        "StoreGate key for the xAOD::TriggerMenuJson L1 configuration object"};
+
+      Gaudi::Property< std::string > m_metaNameJSON_hltps {this, "JSONMetaObjectNameHLTPS", "TriggerMenuJson_HLTPS",
+        "StoreGate key for the xAOD::TriggerMenuJson HLT prescales configuration object"};
+
+      Gaudi::Property< std::string > m_metaNameJSON_l1ps {this, "JSONMetaObjectNameL1PS", "TriggerMenuJson_L1PS",
+        "StoreGate key for the xAOD::TriggerMenuJson L1 prescales configuration object"};
+
+      Gaudi::Property< std::string > m_metaNameJSON_bg {this, "JSONMetaObjectNameBunchgroup", "TriggerMenuJson_BG",
+        "StoreGate key for the xAOD::TriggerMenuJson BunchGroup configuration object"};
+      /// @}
 
       Gaudi::Property<bool> m_stopOnFailure{this, "StopOnFailure", true, "Flag for stopping the job in case of a failure"};
       /// Internal state of the service
       bool m_isInFailure;
 
-      /// The configuration objects copied from all input files
+      /// 
+      /// @name The configuration objects copied from all input files. R1 and R2 AOD
+      /// @{
       std::unique_ptr<xAOD::TriggerMenuAuxContainer> m_tmcAux;
-      /// The configuration objects copied from all input files
       std::unique_ptr<xAOD::TriggerMenuContainer> m_tmc;
 
+      // The menu currently being used by each slot (wrapped 'const xAOD::TriggerMenu' ptr)
+      SG::SlotSpecificObj<MenuPtrWrapper> m_menu;
+      /// @}
+
+      /// 
+      /// @name The configuration objects copied from all input files. R3 AOD
+      /// @{
+      std::unique_ptr<xAOD::TriggerMenuJsonAuxContainer> m_hltJsonAux;
+      std::unique_ptr<xAOD::TriggerMenuJsonContainer> m_hltJson;
+      std::unique_ptr<xAOD::TriggerMenuJsonAuxContainer> m_l1JsonAux;
+      std::unique_ptr<xAOD::TriggerMenuJsonContainer> m_l1Json;
+      std::unique_ptr<xAOD::TriggerMenuJsonAuxContainer> m_hltpsJsonAux;
+      std::unique_ptr<xAOD::TriggerMenuJsonContainer> m_hltpsJson;
+      std::unique_ptr<xAOD::TriggerMenuJsonAuxContainer> m_l1psJsonAux;
+      std::unique_ptr<xAOD::TriggerMenuJsonContainer> m_l1psJson;
+      std::unique_ptr<xAOD::TriggerMenuJsonAuxContainer> m_bgJsonAux;
+      std::unique_ptr<xAOD::TriggerMenuJsonContainer> m_bgJson;
+
+      // The menu JSONs being used in the current event by each slot (wrapped 'const xAOD::TriggerMenuJson' ptr)
+      SG::SlotSpecificObj<TriggerMenuJsonPtrWrapper> m_currentHltJson;
+      SG::SlotSpecificObj<TriggerMenuJsonPtrWrapper> m_currentL1Json;
+      SG::SlotSpecificObj<TriggerMenuJsonPtrWrapper> m_currentHltpsJson;
+      SG::SlotSpecificObj<TriggerMenuJsonPtrWrapper> m_currentL1psJson;
+      SG::SlotSpecificObj<TriggerMenuJsonPtrWrapper> m_currentBgJson;
+
+      // The decoded menu JSON data stored in ptree objects
+      SG::SlotSpecificObj<HLTMenu> m_currentHlt;
+      SG::SlotSpecificObj<L1Menu> m_currentL1;
+      SG::SlotSpecificObj<HLTPrescalesSet> m_currentHltps;
+      SG::SlotSpecificObj<L1PrescalesSet> m_currentL1ps;
+      SG::SlotSpecificObj<L1BunchGroupSet> m_currentBg;
+      /// @}
+
       /// The mutex used to to restrict access to m_tmc when it is being written to
       std::shared_mutex m_sharedMutex;
 
-      // The menu currently being used by each slot (wrapped 'const xAOD::TriggerMenu' ptr)
-      SG::SlotSpecificObj<MenuPtrWrapper> m_menu;
 
+      /// 
+      /// @name The legacy configuration objects which are populated either from a R1, R2 TriggerMenuContainer or the R3 JSONs
+      /// @{
       /// The "translated" LVL1 configuration object
       SG::SlotSpecificObj<CTPConfig> m_ctpConfig;
       /// The "translated" HLT configuration object
@@ -191,12 +305,20 @@ namespace TrigConf {
       SG::SlotSpecificObj<HLTSequenceList> m_sequenceList;
       /// The "translated" bunch group set object
       SG::SlotSpecificObj<BunchGroupSet> m_bgSet;
+      /// @}
 
       /// Connection to the metadata store
       ServiceHandle< StoreGateSvc > m_metaStore{this, "MetaDataStore", "InputMetaDataStore"};
 
+      /// Is decoded R2 format data available?
+      bool m_triggerMenuContainerAvailable;
+      /// Is decoded R3 format data available?
+      bool m_menuJSONContainerAvailable;
+
    }; // class xAODConfigSvc
 
 } // namespace TrigConf
 
+
+
 #endif // TRIGCONFXAOD_XAODCONFIGSVC_H
diff --git a/Trigger/TrigConfiguration/TrigConfxAOD/src/xAODMenuWriterMT.cxx b/Trigger/TrigConfiguration/TrigConfxAOD/src/xAODMenuWriterMT.cxx
index 36bfe6108720a5ce53e75ce1b11a3fc60febfce9..1845f1253332b7743045ac61555f1c8d2ad8e521 100644
--- a/Trigger/TrigConfiguration/TrigConfxAOD/src/xAODMenuWriterMT.cxx
+++ b/Trigger/TrigConfiguration/TrigConfxAOD/src/xAODMenuWriterMT.cxx
@@ -17,10 +17,13 @@
 #include "TrigConfHLTData/HLTSignature.h"
 #include "TrigConfHLTData/HLTTriggerElement.h"
 #include "TrigConfHLTData/HLTSequenceList.h"
+#include "TrigConfHLTData/HLTPrescale.h"
 
 // EDM include(s):
 #include "xAODTrigger/TriggerMenu.h"
 #include "xAODTrigger/TriggerMenuAuxContainer.h"
+#include "xAODTrigger/TriggerMenuJson.h"
+#include "xAODTrigger/TriggerMenuJsonAuxContainer.h"
 
 // Local include(s):
 #include "xAODMenuWriterMT.h"
@@ -44,8 +47,7 @@ namespace TrigConf {
 
       // 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_DEBUG( " EventObjectName   = " << m_eventName );
       ATH_MSG_VERBOSE( "TrigConfigSvc = " << m_trigConf );
       ATH_MSG_VERBOSE( "MetaDataStore = " << m_metaStore );
 
@@ -56,19 +58,81 @@ namespace TrigConf {
       CHECK( m_eventName.initialize() ); // WriteHandleKey
 
       CHECK( m_HLTMenuKey.initialize(m_isHLTJSONConfig) ); // ReadHandleKey
+      CHECK( m_HLTPrescaleSetInputKey.initialize(m_isHLTJSONConfig) ); // ReadCondHandleKey
+
       CHECK( m_L1MenuKey.initialize(m_isL1JSONConfig) ); // ReadHandleKey
- 
+      CHECK( m_L1PrescaleSetInputKey.initialize(m_isL1JSONConfig) ); // ReadCondHandleKey
+
       // 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 );
+      if (m_writexAODTriggerMenu) {
+
+         ATH_MSG_DEBUG( "xAOD::TriggerMenuAuxContainer MetaObjectName    = " << m_metaName );
+
+         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 ) );
+      }
+
+      if (m_writexAODTriggerMenuJson) {
+
+         if (!m_isHLTJSONConfig) {
+            ATH_MSG_ERROR("Require IsHLTJSONConfig to be TRUE when WritexAODTriggerMenuJson is TRUE");
+            return StatusCode::FAILURE;
+         }
+
+         if (!m_isL1JSONConfig) {
+            ATH_MSG_ERROR("Require IsL1JSONConfig to be TRUE when WritexAODTriggerMenuJson is TRUE");
+            return StatusCode::FAILURE;
+         }
+
+         // HLT JSON object - contains HLT menus
+         xAOD::TriggerMenuJsonAuxContainer* aux_hlt = new xAOD::TriggerMenuJsonAuxContainer();
+         m_menuJSON_hlt = new xAOD::TriggerMenuJsonContainer();
+         m_menuJSON_hlt->setStore( aux_hlt );
 
-      // Record the trigger configuration metadata into it:
-      CHECK( m_metaStore->record( aux, m_metaName + "Aux." ) );
-      CHECK( m_metaStore->record( m_tmc, m_metaName ) );
+         CHECK( m_metaStore->record( aux_hlt, m_metaNameJSON_hlt + "Aux." ) );
+         CHECK( m_metaStore->record( m_menuJSON_hlt, m_metaNameJSON_hlt ) );
+
+         // L1 JSON object - contains L1 menus
+         xAOD::TriggerMenuJsonAuxContainer* aux_l1 = new xAOD::TriggerMenuJsonAuxContainer();
+         m_menuJSON_l1 = new xAOD::TriggerMenuJsonContainer();
+         m_menuJSON_l1->setStore( aux_l1 );
+
+         CHECK( m_metaStore->record( aux_l1, m_metaNameJSON_l1 + "Aux." ) );
+         CHECK( m_metaStore->record( m_menuJSON_l1, m_metaNameJSON_l1 ) );
+
+         // HLT PS JSON object - contains prescales sets for HLT menus
+         xAOD::TriggerMenuJsonAuxContainer* aux_hltps = new xAOD::TriggerMenuJsonAuxContainer();
+         m_menuJSON_hltps = new xAOD::TriggerMenuJsonContainer();
+         m_menuJSON_hltps->setStore( aux_hltps );
+
+         CHECK( m_metaStore->record( aux_hltps, m_metaNameJSON_hltps + "Aux." ) );
+         CHECK( m_metaStore->record( m_menuJSON_hltps, m_metaNameJSON_hltps ) );
+
+         // L1 PS JSON object - contains prescales sets for L1 menus
+         xAOD::TriggerMenuJsonAuxContainer* aux_l1ps = new xAOD::TriggerMenuJsonAuxContainer();
+         m_menuJSON_l1ps = new xAOD::TriggerMenuJsonContainer();
+         m_menuJSON_l1ps->setStore( aux_l1ps );
+
+         CHECK( m_metaStore->record( aux_l1ps, m_metaNameJSON_l1ps + "Aux." ) );
+         CHECK( m_metaStore->record( m_menuJSON_l1ps, m_metaNameJSON_l1ps ) );
+
+         // Bunchgroup JSON object - contains bungchgroup configuration
+         // TODO
+         // xAOD::TriggerMenuJsonAuxContainer* aux_bg = new xAOD::TriggerMenuJsonAuxContainer();
+         // m_menuJSON_bg = new xAOD::TriggerMenuJsonContainer();
+         // m_menuJSON_bg->setStore( aux_bg );
+
+         // CHECK( m_metaStore->record( aux_bg, m_metaNameJSON_bg + "Aux." ) );
+         // CHECK( m_metaStore->record( m_menuJSON_bg, m_metaNameJSON_bg ) );
+      }
 
       // Return gracefully:
       return StatusCode::SUCCESS;
@@ -76,61 +140,143 @@ namespace TrigConf {
 
    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) ) );
+      std::unique_ptr<xAOD::TrigConfKeys> keys;
+      if (m_writexAODTriggerMenuJson) {
+         SG::ReadHandle<TrigConf::HLTMenu> hltMenuHandle( m_HLTMenuKey, ctx );
+         SG::ReadCondHandle<TrigConf::L1PrescalesSet> l1PSHandle( m_L1PrescaleSetInputKey, ctx );
+         SG::ReadCondHandle<TrigConf::HLTPrescalesSet> hltPSHandle( m_HLTPrescaleSetInputKey, ctx );
+         ATH_CHECK( hltMenuHandle.isValid() );
+         ATH_CHECK( l1PSHandle.isValid() );
+         ATH_CHECK( hltPSHandle.isValid() );
+         keys = std::make_unique<xAOD::TrigConfKeys>(
+           hltMenuHandle->smk(),
+           l1PSHandle->psk(),
+           hltPSHandle->psk() );
+      } else { // Fall back to R2 TrigConfSvc. Expect this to stop working in the near future (2021+)
+         keys = std::make_unique<xAOD::TrigConfKeys>(
+           m_trigConf->masterKey(),
+           m_trigConf->lvl1PrescaleKey(),
+           m_trigConf->hltPrescaleKey() );
+      }
 
       // 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() ) );
+         std::make_pair( keys->smk(),
+            std::make_pair( keys->l1psk(),
+                            keys->hltpsk() ) );
+
+
+      SG::WriteHandle<xAOD::TrigConfKeys> trigConfKeysWrite(m_eventName, ctx);
+      ATH_CHECK( trigConfKeysWrite.record( std::move(keys) ) );
 
-      // The followign code must only run on one event at a time
+      // The following 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: "
+      // TODO - Deprecate this in the future. Only keep m_writexAODTriggerMenuJson mode
+      if (m_writexAODTriggerMenu) {
+
+         // 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" );
+         } else {
+
+            // Tell the user what's happening:
+            ATH_MSG_INFO( "Converting configuration with keys SMK: "
                           << ckeys.first << ", L1PSK: " << ckeys.second.first
-                          << ", HLTPSK: " << ckeys.second.second
-                          << " already translated" );
-         return StatusCode::SUCCESS;
-      }
+                          << ", 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( ckeys.first );
+            menu->setL1psk( ckeys.second.first );
+            menu->setHLTpsk( ckeys.second.second );
+
+            if (m_isL1JSONConfig) {
+               CHECK( populateL1FromJSON(menu, ctx) );
+            } else {
+               CHECK( populateL1FromTrigConf(menu) );
+            }
 
-      // Tell the user what's happening:
-      ATH_MSG_INFO( "Converting configuration with keys SMK: "
-                    << ckeys.first << ", L1PSK: " << ckeys.second.first
-                    << ", HLTPSK: " << ckeys.second.second );
+            if (m_isHLTJSONConfig) {
+               CHECK( populateHLTFromJSON(menu, ctx) );
+            } else {
+               CHECK( populateHLTFromTrigConf(menu) );
+            }
 
-      // Apparently not, so let's make a new object:
-      xAOD::TriggerMenu* menu = new xAOD::TriggerMenu();
-      m_tmc->push_back( menu ); // Now owned by MetaDataStore
+            CHECK( populateBunchGroup(menu) ); 
+         } // m_convertedKeys
+      } // m_writexAODTriggerMenu
+
+      if (m_writexAODTriggerMenuJson) {
+
+         if( ! m_converted_smk.insert( ckeys.first ).second ) {
+            ATH_MSG_VERBOSE( "Already converted SMK: " << ckeys.first);
+         } else {
+            ATH_MSG_DEBUG( "Filling HLT information for SMK:" << ckeys.first );
+            SG::ReadHandle<TrigConf::HLTMenu> hltMenuHandle( m_HLTMenuKey, ctx );
+            ATH_CHECK( hltMenuHandle.isValid() );
+            std::stringstream hltTriggerMenuJson;
+            hltMenuHandle->printRaw(hltTriggerMenuJson);
+            xAOD::TriggerMenuJson* hlt = new xAOD::TriggerMenuJson();
+            m_menuJSON_hlt->push_back( hlt ); // Now owned by MetaDataStore
+            hlt->setKey( ckeys.first );
+            hlt->setName( hltMenuHandle->name() );
+            hlt->setPayload( hltTriggerMenuJson.str() );
+            //////////////////////////////////////////////////////////////////////////////
+            ATH_MSG_DEBUG( "Filling L1 information for SMK:" << ckeys.first );
+            SG::ReadHandle<TrigConf::L1Menu> l1MenuHandle = SG::makeHandle( m_L1MenuKey, ctx );
+            ATH_CHECK( l1MenuHandle.isValid() );
+            std::stringstream l1TriggerMenuJson;
+            l1MenuHandle->printRaw(l1TriggerMenuJson);
+            xAOD::TriggerMenuJson* l1 = new xAOD::TriggerMenuJson();
+            m_menuJSON_l1->push_back( l1 ); // Now owned by MetaDataStore
+            l1->setKey( ckeys.first );
+            l1->setName( l1MenuHandle->name() );
+            l1->setPayload( l1TriggerMenuJson.str() );
+         }
 
-      //
-      // Set its keys:
-      //
-      menu->setSMK( m_trigConf->masterKey() );
-      menu->setL1psk( m_trigConf->lvl1PrescaleKey() );
-      menu->setHLTpsk( m_trigConf->hltPrescaleKey() );
-
-      if (m_isL1JSONConfig) {
-         CHECK( populateL1FromJSON(menu, ctx) );
-      } else {
-         CHECK( populateL1FromTrigConf(menu) );
-      }
+         if( ! m_converted_hltpsk.insert( ckeys.second.second ).second ) {
+            ATH_MSG_VERBOSE( "Already converted HLTPSK: " << ckeys.second.second);
+         } else {
+            ATH_MSG_DEBUG( "Filling prescale information for HLTPSK:" << ckeys.second.second );
+            SG::ReadCondHandle<TrigConf::HLTPrescalesSet> hltPSHandle( m_HLTPrescaleSetInputKey, ctx );
+            ATH_CHECK( hltPSHandle.isValid() );
+            std::stringstream hltPSJSON;
+            hltPSHandle->printRaw(hltPSJSON);
+            xAOD::TriggerMenuJson* hltps = new xAOD::TriggerMenuJson();
+            m_menuJSON_hltps->push_back( hltps ); // Now owned by MetaDataStore
+            hltps->setKey( ckeys.second.second );
+            hltps->setName( hltPSHandle->name() );
+            hltps->setPayload( hltPSJSON.str() );
+         }
 
-      if (m_isHLTJSONConfig) {
-         CHECK( populateHLTFromJSON(menu, ctx) );
-      } else {
-         CHECK( populateHLTFromTrigConf(menu) );
-      }
+         if( ! m_converted_l1psk.insert( ckeys.second.first ).second ) {
+            ATH_MSG_VERBOSE( "Already converted LVL1PSK: " << ckeys.second.first);
+         } else {
+            ATH_MSG_DEBUG( "Filling prescale information for LVL1PSK:" << ckeys.second.first );
+            SG::ReadCondHandle<TrigConf::L1PrescalesSet> l1PSHandle( m_L1PrescaleSetInputKey, ctx );
+            ATH_CHECK( l1PSHandle.isValid() );
+            std::stringstream l1PSJSON;
+            l1PSHandle->printRaw(l1PSJSON);
+            xAOD::TriggerMenuJson* l1ps = new xAOD::TriggerMenuJson();
+            m_menuJSON_l1ps->push_back( l1ps ); // Now owned by MetaDataStore
+            l1ps->setKey( ckeys.second.first );
+            l1ps->setName( l1PSHandle->name() );
+            l1ps->setPayload( l1PSJSON.str() );
+         }
 
-      CHECK( populateBunchGroup(menu) ); 
+         //
+         // TODO: bg
+         //
+      }
 
       // Return gracefully:
       return StatusCode::SUCCESS;
@@ -146,6 +292,16 @@ namespace TrigConf {
       const size_t nL1Items = l1MenuHandle->size();
       ATH_MSG_DEBUG("Configuring from " << m_L1MenuKey << " with " << nL1Items << " L1 items");
 
+      SG::ReadCondHandle<TrigConf::L1PrescalesSet> l1PSHandle( m_L1PrescaleSetInputKey, ctx );
+      ATH_CHECK( l1PSHandle.isValid() );
+      const size_t nL1ItemsPS = l1PSHandle->size();
+      ATH_MSG_DEBUG("Prescales from " << m_L1PrescaleSetInputKey << " with " << nL1ItemsPS << " L1 items");
+
+      if (nL1Items != nL1ItemsPS) {
+         ATH_MSG_ERROR("Inconsistent number of configured L1 items (" << nL1Items << ") and L1 item prescales (" << nL1ItemsPS << ")");
+         return StatusCode::FAILURE;
+      }
+
       std::vector< uint16_t > ctpIds;
       std::vector< std::string > itemNames;
       std::vector< float > itemPrescales;
@@ -158,7 +314,8 @@ namespace TrigConf {
          // Extract the information:
          ctpIds.push_back( l1.ctpId() );
          itemNames.push_back( l1.name() );
-         itemPrescales.push_back( 1.0 ); // TODO
+         const TrigConf::L1PrescalesSet::L1Prescale l1ps = l1PSHandle->prescale(l1.name());
+         itemPrescales.push_back( l1ps.prescale );
 
          // Some verbose information:
          ATH_MSG_VERBOSE( "  \"" << itemNames.back() << "\" CTP Id = "
@@ -184,6 +341,16 @@ namespace TrigConf {
       const size_t nChains = hltMenuHandle->size();
       ATH_MSG_DEBUG("Configuring from " << m_HLTMenuKey << " with " << nChains << " chains");
 
+      SG::ReadCondHandle<TrigConf::HLTPrescalesSet> hltPSHandle( m_HLTPrescaleSetInputKey, ctx );
+      ATH_CHECK( hltPSHandle.isValid() );
+      const size_t nChainsPS = hltPSHandle->size();
+      ATH_MSG_DEBUG("Prescales from " << m_HLTPrescaleSetInputKey << " with " << nChains << " chains");
+
+      if (nChains != nChainsPS) {
+         ATH_MSG_ERROR("Inconsistent number of configured HLT chains (" << nChains << ") and HLT chain prescales (" << nChainsPS << ")");
+         return StatusCode::FAILURE;
+      }
+
       std::vector< uint16_t > chainIds;
       std::vector< std::string > chainNames, chainParentNames;
       std::vector< float > chainPrescales, chainRerunPrescales,
@@ -211,9 +378,10 @@ namespace TrigConf {
          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
+         const TrigConf::HLTPrescalesSet::HLTPrescale hltps = hltPSHandle->prescale(ch.name());
+         chainPrescales.push_back( hltps.prescale );
+         chainRerunPrescales.push_back( -1.0 ); // Unused in Run3
+         chainPassthroughPrescales.push_back( -1.0 ); // Unused in Run3
 
          std::vector<uint32_t> counters;
          std::vector<int> logics;
diff --git a/Trigger/TrigConfiguration/TrigConfxAOD/src/xAODMenuWriterMT.h b/Trigger/TrigConfiguration/TrigConfxAOD/src/xAODMenuWriterMT.h
index f5d67d27da7144af125bf227083c51197e88dc49..da884a40524862b1c216330740b4d3e273d6c97c 100644
--- a/Trigger/TrigConfiguration/TrigConfxAOD/src/xAODMenuWriterMT.h
+++ b/Trigger/TrigConfiguration/TrigConfxAOD/src/xAODMenuWriterMT.h
@@ -24,9 +24,12 @@ extern "C" {
 #include "TrigConfInterfaces/ITrigConfigSvc.h"
 #include "TrigConfData/HLTMenu.h"
 #include "TrigConfData/L1Menu.h"
+#include "TrigConfData/HLTPrescalesSet.h"
+#include "TrigConfData/L1PrescalesSet.h"
 
 // EDM include(s):
 #include "xAODTrigger/TriggerMenuContainer.h"
+#include "xAODTrigger/TriggerMenuJsonContainer.h"
 #include "xAODTrigger/TrigConfKeys.h"
 
 namespace TrigConf {
@@ -66,14 +69,36 @@ namespace TrigConf {
       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",
+      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",
+      SG::ReadHandleKey<TrigConf::L1Menu> m_L1MenuKey {this, "L1TriggerMenu", "DetectorStore+L1TriggerMenu",
         "L1 Menu key, for use if IsJSONConfig=True"};
 
+      SG::ReadCondHandleKey<TrigConf::HLTPrescalesSet> m_HLTPrescaleSetInputKey{this, "HLTPrescales", "HLTPrescales", 
+        "HLT prescales set condition handle"};
+
+      SG::ReadCondHandleKey<TrigConf::L1PrescalesSet> m_L1PrescaleSetInputKey{this, "L1Prescales", "L1Prescales", 
+        "L1 prescales set condition handle"};
+
       Gaudi::Property< std::string > m_metaName {this, "MetaObjectName", "TriggerMenu",
-        "StoreGate key for the configuration object"};
+        "StoreGate key for the xAOD::TriggerMenu configuration object"};
+
+      Gaudi::Property< std::string > m_metaNameJSON_hlt {this, "JSONMetaObjectNameHLT", "TriggerMenuJson_HLT",
+        "StoreGate key for the xAOD::TriggerMenuJson HLT configuration object"};
+
+      Gaudi::Property< std::string > m_metaNameJSON_l1 {this, "JSONMetaObjectNameL1", "TriggerMenuJson_L1",
+        "StoreGate key for the xAOD::TriggerMenuJson L1 configuration object"};
+
+      Gaudi::Property< std::string > m_metaNameJSON_hltps {this, "JSONMetaObjectNameHLTPS", "TriggerMenuJson_HLTPS",
+        "StoreGate key for the xAOD::TriggerMenuJson HLT prescales configuration object"};
+
+      Gaudi::Property< std::string > m_metaNameJSON_l1ps {this, "JSONMetaObjectNameL1PS", "TriggerMenuJson_L1PS",
+        "StoreGate key for the xAOD::TriggerMenuJson L1 prescales configuration object"};
+
+      // TODO
+      // Gaudi::Property< std::string > m_metaNameJSON_bg {this, "JSONMetaObjectNameBunchgroup", "TriggerMenuJson_BG",
+      //   "StoreGate key for the xAOD::TriggerMenuJson BunchGroup configuration object"};
 
       Gaudi::Property< bool > m_isL1JSONConfig {this, "IsL1JSONConfig", true,
         "If converting from a L1 JSON menu (Run3) or from the TrigConfigSvc (Runs 1, 2)"};
@@ -81,6 +106,12 @@ namespace TrigConf {
       Gaudi::Property< bool > m_isHLTJSONConfig {this, "IsHLTJSONConfig", true,
         "If converting from a HLT JSON menu (Run3) or from the TrigConfigSvc (Runs 1, 2)"};
 
+      Gaudi::Property< bool > m_writexAODTriggerMenu {this, "WritexAODTriggerMenu", true,
+        "Flag to control the writing of xAOD::TriggerMenu metadata into the output file. This is the R2 persistent format."}; 
+
+      Gaudi::Property< bool > m_writexAODTriggerMenuJson {this, "WritexAODTriggerMenuJson", true,
+        "Flag to control the writing of xAOD::TriggerMenuJson metadata into the output file. This is the R3 persistent format."};   
+
       ServiceHandle< TrigConf::ITrigConfigSvc > m_trigConf {this, "TrigConfigSvc", "TrigConfigSvc",
         "The TrigConfigSvc"};
 
@@ -100,12 +131,25 @@ namespace TrigConf {
       /// 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
+      /// The configuration object that we are writing when WritexAODTriggerMenu
       mutable xAOD::TriggerMenuContainer* m_tmc;
 
-      /// Trigger configuration keys that are already converted
+      //  The configuration objects that we are writing when WritexAODTriggerMenuJson
+      mutable xAOD::TriggerMenuJsonContainer* m_menuJSON_hlt;
+      mutable xAOD::TriggerMenuJsonContainer* m_menuJSON_l1;
+      mutable xAOD::TriggerMenuJsonContainer* m_menuJSON_hltps;
+      mutable xAOD::TriggerMenuJsonContainer* m_menuJSON_l1ps;
+      // mutable xAOD::TriggerMenuJsonContainer* m_menuJSON_bg;
+
+      /// Trigger configuration keys that are already converted when WritexAODTriggerMenu is true
       mutable std::set< TrigKey_t > m_convertedKeys;
 
+      /// Trigger configuration keys that are already converted when WritexAODTriggerMenuJson is true
+      mutable std::set< uint32_t > m_converted_smk;
+      mutable std::set< uint32_t > m_converted_hltpsk;
+      mutable std::set< uint32_t > m_converted_l1psk;
+      // mutable std::set< uint32_t > m_converted_bg;
+
       /// The mutex to prevent us from writing more than one configuration at a time
       mutable std::mutex m_mutex;
 
diff --git a/Trigger/TrigMonitoring/TrigEgammaMonitoring/src/TrigEgammaMonitorTagAndProbeAlgorithm.cxx b/Trigger/TrigMonitoring/TrigEgammaMonitoring/src/TrigEgammaMonitorTagAndProbeAlgorithm.cxx
index 055409940bbcbb8afdfcb8e4ecea028797b88064..f72c0cca47089e06b23480234aac92c62f68fecc 100644
--- a/Trigger/TrigMonitoring/TrigEgammaMonitoring/src/TrigEgammaMonitorTagAndProbeAlgorithm.cxx
+++ b/Trigger/TrigMonitoring/TrigEgammaMonitoring/src/TrigEgammaMonitorTagAndProbeAlgorithm.cxx
@@ -18,7 +18,6 @@
  **********************************************************************/
 
 #include "TrigEgammaMonitorTagAndProbeAlgorithm.h"
-#include "TrigConfxAOD/xAODConfigTool.h"
 #include "GaudiKernel/SystemOfUnits.h"
 #include "string"
 #include <algorithm>
@@ -28,7 +27,6 @@
 
 //**********************************************************************
 using namespace Trig;
-using namespace TrigConf;
 using namespace xAOD;
 using namespace boost;
 
diff --git a/Trigger/TrigSteer/L1Decoder/python/L1DecoderConfig.py b/Trigger/TrigSteer/L1Decoder/python/L1DecoderConfig.py
index ada3b3b844a874657516ddafba1dafb5c24409f3..712be1df152c19c3328042c7210443923c7e4d15 100644
--- a/Trigger/TrigSteer/L1Decoder/python/L1DecoderConfig.py
+++ b/Trigger/TrigSteer/L1Decoder/python/L1DecoderConfig.py
@@ -208,7 +208,6 @@ def L1DecoderCfg(flags, seqName = None):
     acc.merge( TrigConfigSvcCfg( flags ) )
     acc.merge( HLTPrescaleCondAlgCfg( flags ) )
 
-
     Configurable.configurableRun3Behavior -= 1
 
     return acc
diff --git a/Trigger/TriggerCommon/TriggerJobOpts/python/TriggerConfig.py b/Trigger/TriggerCommon/TriggerJobOpts/python/TriggerConfig.py
index f0e7b9ccf2c3bdf21c3cf8dce1b3d5788b5d678b..b58e7551db0858505e0fb4b78c210231570ba1bc 100644
--- a/Trigger/TriggerCommon/TriggerJobOpts/python/TriggerConfig.py
+++ b/Trigger/TriggerCommon/TriggerJobOpts/python/TriggerConfig.py
@@ -430,6 +430,11 @@ def triggerPOOLOutputCfg(flags, edmSet):
     menuwriter.IsL1JSONConfig = True
     acc.addEventAlgo( menuwriter )
 
+    # Schedule the insertion of L1 prescales into the conditions store
+    # Required for metadata production
+    from TrigConfigSvc.TrigConfigSvcCfg import  L1PrescaleCondAlgCfg
+    acc.merge( L1PrescaleCondAlgCfg( flags ) )
+
     # Add metadata to the output stream
     streamAlg.MetadataItemList += [ "xAOD::TriggerMenuContainer#*", "xAOD::TriggerMenuAuxContainer#*" ]
 
diff --git a/Trigger/TriggerCommon/TriggerJobOpts/python/TriggerConfigGetter.py b/Trigger/TriggerCommon/TriggerJobOpts/python/TriggerConfigGetter.py
index 95a1eebefd417fd66e0ec1dc47595a7d7af43d7a..8616b857d9d99fe92db46b718e4d396e1ef8134b 100644
--- a/Trigger/TriggerCommon/TriggerJobOpts/python/TriggerConfigGetter.py
+++ b/Trigger/TriggerCommon/TriggerJobOpts/python/TriggerConfigGetter.py
@@ -172,7 +172,7 @@ class TriggerConfigGetter(Configured):
         self.l1Folders      = TriggerFlags.dataTakingConditions()=='FullTrigger' or TriggerFlags.dataTakingConditions()=='Lvl1Only'
         self.hltFolders     = TriggerFlags.dataTakingConditions()=='FullTrigger' or TriggerFlags.dataTakingConditions()=='HltOnly'
         self.isRun1Data     = False 
-        self.hasxAODMeta    = ("metadata_items" in metadata and any(('TriggerMenu' in key) for key in metadata["metadata_items"].keys()))
+        self.hasxAODMeta    = ("metadata_items" in metadata and any(('TriggerMenu' or 'MenuJSON' in key) for key in metadata["metadata_items"].keys()))
         if globalflags.DataSource()=='data':
             from RecExConfig.AutoConfiguration  import GetRunNumber
             runNumber = GetRunNumber()
@@ -437,6 +437,8 @@ class TriggerConfigGetter(Configured):
         # Add the algorithm creating the trigger configuration metadata for
         # the output:
         try: 
+            writeTriggerMenu = True
+            writeMenuJSON = False
             if TriggerFlags.EDMDecodingVersion() <= 2:
                 from TrigConfxAOD.TrigConfxAODConf import TrigConf__xAODMenuWriter
                 topAlgs += TrigConf__xAODMenuWriter( OverwriteEventObj = True )
@@ -445,15 +447,36 @@ class TriggerConfigGetter(Configured):
                 menuwriter = TrigConf__xAODMenuWriterMT()
                 menuwriter.IsHLTJSONConfig = True
                 menuwriter.IsL1JSONConfig = True
-                topAlgs += menuwriter
+                menuwriter.WritexAODTriggerMenu = True # This should be removed in the future
+                menuwriter.WritexAODMenuJSON = True
+                writeTriggerMenu = menuwriter.WritexAODTriggerMenu
+                writeMenuJSON = menuwriter.WritexAODMenuJSON
 
-            # The metadata objects to add to the output:
-            metadataItems = [ "xAOD::TriggerMenuContainer#TriggerMenu",
-                              "xAOD::TriggerMenuAuxContainer#TriggerMenuAux." ]
+                topAlgs += menuwriter
 
             # Set up the metadata for the output ESD and AOD:
             from RecExConfig.ObjKeyStore import objKeyStore
-            objKeyStore.addManyTypesMetaData( metadataItems )
+
+            # The metadata objects to add to the output:
+            if writeTriggerMenu:
+                metadataItems = [ "xAOD::TriggerMenuContainer#TriggerMenu",
+                                  "xAOD::TriggerMenuAuxContainer#TriggerMenuAux." ]
+                objKeyStore.addManyTypesMetaData( metadataItems )
+
+            if writeMenuJSON:
+                metadataItems = [ "xAOD::TriggerMenuJSONContainer#MenuJSON_HLT",
+                                  "xAOD::TriggerMenuJSONAuxContainer#MenuJSON_HLTAux.",
+                                  "xAOD::TriggerMenuJSONContainer#MenuJSON_L1",
+                                  "xAOD::TriggerMenuJSONAuxContainer#MenuJSON_L1Aux.",
+                                  "xAOD::TriggerMenuJSONContainer#MenuJSON_HLTPS",
+                                  "xAOD::TriggerMenuJSONAuxContainer#MenuJSON_HLTPSAux.",
+                                  "xAOD::TriggerMenuJSONContainer#MenuJSON_L1PS",
+                                  "xAOD::TriggerMenuJSONAuxContainer#MenuJSON_L1PSAux.",
+                                  # "xAOD::TriggerMenuJSONContainer#MenuJSON_BG", // TODO
+                                  # "xAOD::TriggerMenuJSONAuxContainer#MenuJSON_BGAux.", // TODO
+                                ]
+                objKeyStore.addManyTypesMetaData( metadataItems )
+
         except ImportError: # don't want to branch in rel 18
             pass
 
diff --git a/Trigger/TriggerCommon/TriggerJobOpts/share/runHLT_standalone_newJO.py b/Trigger/TriggerCommon/TriggerJobOpts/share/runHLT_standalone_newJO.py
index 65e1efbcaf6772afc9e23a033b0b8062b0e4a89f..56efb6bc4cf9669f493b93fb5a04c2ad7b2244c8 100644
--- a/Trigger/TriggerCommon/TriggerJobOpts/share/runHLT_standalone_newJO.py
+++ b/Trigger/TriggerCommon/TriggerJobOpts/share/runHLT_standalone_newJO.py
@@ -88,6 +88,10 @@ acc.merge( triggerRunCfg( flags, seqName = "AthMasterSeq", menu=generateHLTMenu
 from RegionSelector.RegSelConfig import regSelCfg
 acc.merge( regSelCfg( flags ) )
 
+# The L1 presacles do not get created in the avoce menu setup
+from TrigConfigSvc.TrigConfigSvcCfg import createL1PrescalesFileFromMenu
+createL1PrescalesFileFromMenu(flags)
+
 
 acc.getEventAlgo( "TrigSignatureMoniMT" ).OutputLevel=DEBUG
 acc.getEventAlgo( "L1Decoder" ).ctpUnpacker.UseTBPBits=True # test setup