diff --git a/Control/AthToolSupport/AsgExampleTools/AsgExampleTools/UnitTestService1.h b/Control/AthToolSupport/AsgExampleTools/AsgExampleTools/UnitTestService1.h
index f02c1b80b1db0c7b1370b5cfeae5961c58591bb3..54987f72a871179dffe9accff65b6dfb93808d05 100644
--- a/Control/AthToolSupport/AsgExampleTools/AsgExampleTools/UnitTestService1.h
+++ b/Control/AthToolSupport/AsgExampleTools/AsgExampleTools/UnitTestService1.h
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration
+  Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
 */
 
 /// @author Nils Krumnack
@@ -22,8 +22,7 @@ namespace asg
   /// This allows to unit test the various capabilities of
   /// AnaToolHandle in a controlled fashion.
 
-  struct UnitTestService1 : virtual public IUnitTestService1,
-                            public AsgService
+  struct UnitTestService1 : extends<AsgService, IUnitTestService1>
   {
     /// \brief standard constructor
   public:
diff --git a/Control/AthToolSupport/AsgExampleTools/Root/UnitTestService1.cxx b/Control/AthToolSupport/AsgExampleTools/Root/UnitTestService1.cxx
index d54453caca35eb0a5cc047b1dce9702075f2a201..ee5b2d18a2a30f84023761666da85ecbeae3bf28 100644
--- a/Control/AthToolSupport/AsgExampleTools/Root/UnitTestService1.cxx
+++ b/Control/AthToolSupport/AsgExampleTools/Root/UnitTestService1.cxx
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
+  Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
 */
 
 /// @author Nils Krumnack
@@ -27,10 +27,8 @@ namespace asg
 {
   UnitTestService1 ::
   UnitTestService1 (const std::string& name, ISvcLocator* pSvcLocator)
-    : AsgService (name, pSvcLocator)
+    : base_class (name, pSvcLocator)
   {
-    declareServiceInterface<IUnitTestService1>();
-
     declareProperty ("propertyInt", m_propertyInt, "the integer property");
     declareProperty ("propertyString", m_propertyString, "the string property");
     declareProperty ("initializeFail", m_initializeFail, "whether initialize should fail");
diff --git a/Control/AthToolSupport/AsgServices/AsgServices/AsgService.h b/Control/AthToolSupport/AsgServices/AsgServices/AsgService.h
index 5c981396cd0feb188d4d6375e1c5ead07b305121..9612ba095723836dd5a6fdb0a9810991af1834a3 100644
--- a/Control/AthToolSupport/AsgServices/AsgServices/AsgService.h
+++ b/Control/AthToolSupport/AsgServices/AsgServices/AsgService.h
@@ -39,17 +39,12 @@ namespace asg
   /// Loosely based on the \ref AsgTool implementation.
 
   class AsgService :
-#ifndef XAOD_STANDALONE
     public extends<AsgServiceBase, IAsgService>
-#else
-    public AsgServiceBase, public virtual IAsgService
-#endif
   {
   public:
     AsgService (const std::string& name,
                 ISvcLocator* pSvcLocator);
 
-
     /// set up/tear down functions
     /// \{
     virtual StatusCode initialize ();
@@ -59,28 +54,8 @@ namespace asg
     /// Print the state of the service
     virtual void print() const;
 
-    /// add the given interface to the list of interfaces
-    template<typename T> void declareServiceInterface ();
-
-
-#ifndef XAOD_STANDALONE
-  private:
-    /// list of interfaces we have
-    std::vector<std::pair<const InterfaceID& (*)(),void *(*)(AsgService*)>> m_interfaces;
-#endif
-
   }; // class AsgService
 
-
-
-  template<typename T>
-  void AsgService :: declareServiceInterface ()
-  {
-#ifndef XAOD_STANDALONE
-    m_interfaces.emplace_back (T::interfaceID, [] (AsgService *self) -> void* {return dynamic_cast<T*>(self);});
-#endif
-  }
-
 } // namespace asg
 
 #endif // ASGSERVICES_ASGSERVICE_H
diff --git a/Control/AthToolSupport/AsgServices/AsgServices/IAsgService.h b/Control/AthToolSupport/AsgServices/AsgServices/IAsgService.h
index ec2fbde00fbca233460c330e24f485bc7ecad432..d40ef2035494a0a46c050532209a67e88914af53 100644
--- a/Control/AthToolSupport/AsgServices/AsgServices/IAsgService.h
+++ b/Control/AthToolSupport/AsgServices/AsgServices/IAsgService.h
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration
+  Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
 */
 
 /// @author Nils Krumnack
@@ -13,16 +13,7 @@
 
 // Local include(s):
 #include "AsgMessaging/INamedInterface.h"
-
-#ifdef XAOD_STANDALONE
-/// \brief standalone version of the Gaudi interface declaration
-///
-/// This can't be a no-op, because the Gaudi version needs to be
-/// followed by a semicolon, so we need a statement that requires to
-/// be followed by a semi-colon.
-#define DeclareInterfaceID(iface, major, minor) \
-  static constexpr std::nullptr_t interfaceID = nullptr
-#endif
+#include "AsgTools/Interfaces.h"
 
 namespace asg
 {
diff --git a/Control/AthToolSupport/AsgServices/Root/AsgService.cxx b/Control/AthToolSupport/AsgServices/Root/AsgService.cxx
index e4b1aace01844f9fd92cca020a9494172aeb918f..178f1720c67b8b7e28991abad64dbf819c4d0ad0 100644
--- a/Control/AthToolSupport/AsgServices/Root/AsgService.cxx
+++ b/Control/AthToolSupport/AsgServices/Root/AsgService.cxx
@@ -21,10 +21,10 @@ namespace asg
 #ifndef XAOD_STANDALONE
     : base_class(name, pSvcLocator)
 #else
-      : AsgServiceBase(name)
+    : base_class(name)
 #endif
    {
-     (void) pSvcLocator;
+     (void) pSvcLocator;  // suppress compiler warning in XAOD_STANDALONE
    }
 
   StatusCode AsgService ::
diff --git a/Control/AthToolSupport/AsgTools/AsgTools/AsgComponent.h b/Control/AthToolSupport/AsgTools/AsgTools/AsgComponent.h
index dc7cdcdf4e579db0dc397e30453a166f76354317..58cbfbaf08869f7ea1c343f6fb9f24fefd81ba9d 100644
--- a/Control/AthToolSupport/AsgTools/AsgTools/AsgComponent.h
+++ b/Control/AthToolSupport/AsgTools/AsgTools/AsgComponent.h
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration
+  Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
 */
 
 /// \author Nils Krumnack
@@ -15,6 +15,7 @@
 #include <AsgMessaging/INamedInterface.h>
 #include <AsgMessaging/MessageCheck.h>
 #include <AsgMessaging/MsgLevel.h>
+#include <AsgTools/Interfaces.h>
 #include <memory>
 #include <vector>
 
diff --git a/Control/AthToolSupport/AsgTools/AsgTools/Interfaces.h b/Control/AthToolSupport/AsgTools/AsgTools/Interfaces.h
new file mode 100644
index 0000000000000000000000000000000000000000..82a3f170c75cfa3d510d29b0d97791ca7ca04e38
--- /dev/null
+++ b/Control/AthToolSupport/AsgTools/AsgTools/Interfaces.h
@@ -0,0 +1,40 @@
+/*
+  Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
+*/
+#ifndef ASGTOOLS_INTERFACES_H
+#define ASGTOOLS_INTERFACES_H
+
+///
+/// Standalone versions of Gaudi interface declarations.
+//
+#if defined(XAOD_STANDALONE)
+
+/// This can't be a no-op, because the Gaudi version needs to be
+/// followed by a semicolon, so we need a statement that requires to
+/// be followed by a semi-colon.
+#define DeclareInterfaceID(iface, major, minor) \
+  static_assert(true)
+
+
+/// See GaudiKernel/extend_interfaces.h
+template <typename... Interfaces>
+struct extend_interfaces : virtual public Interfaces... {
+};
+
+
+/// See GaudiKernel/extends.h
+template <typename BASE, typename... Interfaces>
+struct extends : public BASE, virtual public extend_interfaces<Interfaces...> {
+  using base_class = extends;
+  using BASE::BASE;
+};
+
+
+/// See GaudiKernel/implements.h
+template <typename... Interfaces>
+struct implements : virtual public extend_interfaces<Interfaces...> {
+  using base_class = implements<Interfaces...>;
+};
+
+#endif
+#endif