diff --git a/GaudiKernel/include/Gaudi/Concepts.h b/GaudiKernel/include/Gaudi/Concepts.h
new file mode 100644
index 0000000000000000000000000000000000000000..c443698a70f97a0cde8a9ba694b3ac54c00f1618
--- /dev/null
+++ b/GaudiKernel/include/Gaudi/Concepts.h
@@ -0,0 +1,22 @@
+/***********************************************************************************\
+* (c) Copyright 2025 CERN for the benefit of the LHCb and ATLAS collaborations      *
+*                                                                                   *
+* This software is distributed under the terms of the Apache version 2 licence,     *
+* copied verbatim in the file "LICENSE".                                            *
+*                                                                                   *
+* In applying this licence, CERN does not waive the privileges and immunities       *
+* granted to it by virtue of its status as an Intergovernmental Organization        *
+* or submit itself to any jurisdiction.                                             *
+\***********************************************************************************/
+#pragma once
+
+#include <concepts>
+
+class InterfaceID;
+
+namespace Gaudi {
+  template <typename T>
+  concept IsInterface = requires {
+    { T::interfaceID() } -> std::same_as<const InterfaceID&>;
+  };
+} // namespace Gaudi
diff --git a/GaudiKernel/include/GaudiKernel/ServiceHandle.h b/GaudiKernel/include/GaudiKernel/ServiceHandle.h
index 20c4aea33a2c70741f87313c3cfa152f2fcc0dad..067b9da8d5544a3f45a3b3daad70f30f2ad7eac3 100644
--- a/GaudiKernel/include/GaudiKernel/ServiceHandle.h
+++ b/GaudiKernel/include/GaudiKernel/ServiceHandle.h
@@ -1,5 +1,5 @@
 /***********************************************************************************\
-* (c) Copyright 1998-2024 CERN for the benefit of the LHCb and ATLAS collaborations *
+* (c) Copyright 1998-2025 CERN for the benefit of the LHCb and ATLAS collaborations *
 *                                                                                   *
 * This software is distributed under the terms of the Apache version 2 licence,     *
 * copied verbatim in the file "LICENSE".                                            *
@@ -12,6 +12,7 @@
 #define GAUDIKERNEL_SERVICEHANDLE_H
 
 // Includes
+#include <Gaudi/Concepts.h>
 #include <GaudiKernel/Bootstrap.h>
 #include <GaudiKernel/GaudiException.h>
 #include <GaudiKernel/GaudiHandle.h>
@@ -94,9 +95,27 @@ public:
 
 protected:
   /** Do the real retrieval of the Service. */
-  StatusCode retrieve( T*& service ) const override {
+  StatusCode retrieve( T*& service ) const override { return i_retrieve( service ); }
+
+  /// retrieve the service for ServiceHandles<ISomeInterfaces>
+  template <Gaudi::IsInterface I = T>
+  StatusCode i_retrieve( I*& service ) const {
     const ServiceLocatorHelper helper( *serviceLocator(), GaudiHandleBase::messageName(), this->parentName() );
-    return helper.getService( GaudiHandleBase::typeAndName(), true, T::interfaceID(), (void**)&service );
+    return helper.getService( GaudiHandleBase::typeAndName(), true, I::interfaceID(), (void**)&service );
+  }
+
+  /// retrieve the service for ServiceHandles<ActualService>
+  template <typename I = T>
+    requires( !Gaudi::IsInterface<I> )
+  StatusCode i_retrieve( I*& service ) const {
+    IService* svc = nullptr;
+    return i_retrieve( svc ).andThen( [&] {
+      service = dynamic_cast<I*>( svc );
+      if ( !service )
+        throw GaudiException( "unable to dcast Service " + this->typeAndName() + " to " +
+                                  System::typeinfoName( typeid( T ) ),
+                              this->typeAndName() + " retrieve", StatusCode::FAILURE );
+    } );
   }
 
   //   /** Do the real release of the Service */
diff --git a/GaudiTestSuite/CMakeLists.txt b/GaudiTestSuite/CMakeLists.txt
index f5d318ac9c605cd2bcdafca9ed9f8b38a0421ef2..3207800958976efb250832db6d4cd8cbfd36ccf4 100644
--- a/GaudiTestSuite/CMakeLists.txt
+++ b/GaudiTestSuite/CMakeLists.txt
@@ -108,6 +108,7 @@ gaudi_add_module(GaudiTestSuiteComponents
                          src/ToolHandles/FloatTool.cpp
                          src/NTuple/NTupleWriterProducers.cpp
                          src/NTuple/NTupleWriterImpls.cpp
+                         src/UseSvcWithoutInterface.cpp
                  LINK GaudiKernel
                       Gaudi::Functional
                       GaudiUtilsLib
diff --git a/GaudiTestSuite/src/UseSvcWithoutInterface.cpp b/GaudiTestSuite/src/UseSvcWithoutInterface.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3460ffa5cf3f93862f6b3932baf2f81564828118
--- /dev/null
+++ b/GaudiTestSuite/src/UseSvcWithoutInterface.cpp
@@ -0,0 +1,45 @@
+/***********************************************************************************\
+* (c) Copyright 2025 CERN for the benefit of the LHCb and ATLAS collaborations      *
+*                                                                                   *
+* This software is distributed under the terms of the Apache version 2 licence,     *
+* copied verbatim in the file "LICENSE".                                            *
+*                                                                                   *
+* In applying this licence, CERN does not waive the privileges and immunities       *
+* granted to it by virtue of its status as an Intergovernmental Organization        *
+* or submit itself to any jurisdiction.                                             *
+\***********************************************************************************/
+#include <Gaudi/Algorithm.h>
+#include <Gaudi/Functional/Consumer.h>
+#include <GaudiKernel/Service.h>
+
+namespace Gaudi::TestSuite {
+  class SvcWithoutInterface : public Service {
+  public:
+    using Service::Service;
+
+    StatusCode initialize() override {
+      return Service::initialize().andThen( [this] { info() << "initialized" << endmsg; } );
+    }
+
+    void doSomething() const { info() << "doing something" << endmsg; }
+  };
+  DECLARE_COMPONENT( SvcWithoutInterface )
+
+  class UseSvcWithoutInterface : public Gaudi::Functional::Consumer<void()> {
+  public:
+    UseSvcWithoutInterface( const std::string& name, ISvcLocator* svcLoc )
+        : Consumer( name, svcLoc ), m_svc( "Gaudi::TestSuite::SvcWithoutInterface/SvcWithoutInterface", name ) {}
+    StatusCode initialize() override {
+      return Algorithm::initialize()
+          .andThen( [this] { info() << "initializing..." << endmsg; } )
+          .andThen( [this] { m_svc->doSomething(); } )
+          .andThen( [this] { info() << "initialized" << endmsg; } );
+    }
+    void operator()() const override {}
+
+  private:
+    // Add your member variables here
+    ServiceHandle<SvcWithoutInterface> m_svc;
+  };
+  DECLARE_COMPONENT( UseSvcWithoutInterface )
+} // namespace Gaudi::TestSuite
diff --git a/GaudiTestSuite/tests/pytest/handles/test_svc_without_interface.py b/GaudiTestSuite/tests/pytest/handles/test_svc_without_interface.py
new file mode 100644
index 0000000000000000000000000000000000000000..5a4c268c4b887ee1721b08b176cd6107c1037210
--- /dev/null
+++ b/GaudiTestSuite/tests/pytest/handles/test_svc_without_interface.py
@@ -0,0 +1,53 @@
+#####################################################################################
+# (c) Copyright 2025 CERN for the benefit of the LHCb and ATLAS collaborations      #
+#                                                                                   #
+# This software is distributed under the terms of the Apache version 2 licence,     #
+# copied verbatim in the file "LICENSE".                                            #
+#                                                                                   #
+# In applying this licence, CERN does not waive the privileges and immunities       #
+# granted to it by virtue of its status as an Intergovernmental Organization        #
+# or submit itself to any jurisdiction.                                             #
+#####################################################################################
+
+from GaudiTesting import NO_ERROR_MESSAGES, GaudiExeTest
+
+
+def config():
+    from GaudiConfig2 import Configurables as C
+
+    conf = []
+    alg = C.Gaudi.TestSuite.UseSvcWithoutInterface("UseSvcWithoutInterface")
+    conf.append(alg)
+
+    appMgr = C.ApplicationMgr(
+        TopAlg=[alg],
+        EvtMax=1,
+        EvtSel="NONE",
+    )
+    conf.append(appMgr)
+
+    msgsvc = C.MessageSvc(Format="% F%25W%S%7W%R%T %0W%M")
+    conf.append(msgsvc)
+
+    return conf
+
+
+class Test(GaudiExeTest):
+    command = ["gaudirun.py", f"{__file__}:config"]
+
+    reference = {"messages_count": NO_ERROR_MESSAGES}
+
+    def test_stdout(self, stdout: bytes):
+        extracted_lines = [
+            line.split(None, 2)
+            for line in stdout.splitlines()
+            if line.startswith(b"UseSvcWithoutInterface")
+            or line.startswith(b"SvcWithoutInterface")
+        ]
+        expected_lines = [
+            [b"UseSvcWithoutInterface", b"INFO", b"initializing..."],
+            [b"SvcWithoutInterface", b"INFO", b"initialized"],
+            [b"SvcWithoutInterface", b"INFO", b"doing something"],
+            [b"UseSvcWithoutInterface", b"INFO", b"initialized"],
+        ]
+        assert extracted_lines == expected_lines