diff --git a/src/mo_optimization_utils.f90 b/src/mo_optimization_utils.f90
index 57d1939e9fba20494cd08abe941bb5fc234319dc..d7e48755af6cdbcb14282bbad2854c49cfbf9528 100644
--- a/src/mo_optimization_utils.f90
+++ b/src/mo_optimization_utils.f90
@@ -8,6 +8,7 @@
 module mo_optimization_utils
 
   use mo_kind, only : dp
+  use mo_message, only : error_message
 
   implicit none
 
@@ -24,7 +25,7 @@ module mo_optimization_utils
   abstract interface
     subroutine eval_interface(config, opti_sim)
       use mo_optimization_types, only : config_t, opti_sim_t
-      type(config_t),                                        intent(in)    :: config
+      type(config_t),                                    intent(in)    :: config
       type(opti_sim_t), dimension(:), pointer, optional, intent(inout) :: opti_sim
     end subroutine
   end interface
@@ -33,7 +34,7 @@ module mo_optimization_utils
   !> \details The optional arguments are motivated by likelihood objective functions.
   ! ToDo: eval optional
   interface
-    function objective_interface (parameterset, eval, arg1, arg2, arg3)
+    function objective_interface(parameterset, eval, arg1, arg2, arg3)
       use mo_kind, only : dp
       import eval_interface
       real(dp), intent(in), dimension(:) :: parameterset !< parameter set
@@ -46,4 +47,134 @@ module mo_optimization_utils
     end function objective_interface
   end interface
 
+
+  !> \brief abstract type 'optimizee' to be used by optimizers
+  type, abstract :: optimizee
+  contains
+    !> \brief evaluate the optimizee
+    procedure(evaluate_interface), deferred :: evaluate
+  end type optimizee
+
+  !> \brief Abstract interface for deferred procedures
+  abstract interface
+    function evaluate_interface(self, parameters, sigma, stddev_new, likeli_new) result(value)
+      use mo_kind, only : dp
+      import :: optimizee
+      class(optimizee), intent(inout) :: self
+      real(dp), intent(in), dimension(:) :: parameters !< parameter set
+      real(dp), intent(in), optional     :: sigma      !< likelihood: standard deviation of data
+      real(dp), intent(out), optional    :: stddev_new !< likelihood: standard deviation of errors using parameters
+      real(dp), intent(out), optional    :: likeli_new !< likelihood: likelihood using stddev_new
+      real(dp)                           :: value      !< output value
+    end function evaluate_interface
+  end interface
+
+  !> \brief Optimizee for a simple function: f(vec)
+  type, extends(optimizee) :: function_optimizee
+    procedure(func_interface), pointer, nopass :: func_pointer => null()  !< Pointer to the function
+  contains
+    procedure :: evaluate => evaluate_function
+  end type function_optimizee
+
+  !> \brief Abstract interface for the function pointer
+  abstract interface
+    function func_interface(parameters) result(value)
+      use mo_kind, only : dp
+      real(dp), dimension(:), intent(in) :: parameters !< parameter set
+      real(dp)                           :: value      !< output value
+    end function func_interface
+  end interface
+
+  !> \brief Optimizee for a likelihood function: f(vec, sigma, stddev_new, likeli_new)
+  type, extends(optimizee) :: likelihood_optimizee
+    procedure(likelihood_interface), pointer, nopass :: likelihood_pointer => null()  !< Pointer to the likelihood
+  contains
+    procedure :: evaluate => evaluate_likelihood
+  end type likelihood_optimizee
+
+  !> \brief Abstract interface for the likelihood pointer
+  abstract interface
+    function likelihood_interface(parameters, sigma, stddev_new, likeli_new) result(value)
+      use mo_kind, only : dp
+        real(dp), dimension(:), intent(in) :: parameters !< parameter set
+        real(dp), intent(in), optional     :: sigma      !< standard deviation of data
+        real(dp), intent(out), optional    :: stddev_new !< standard deviation of errors using parameters
+        real(dp), intent(out), optional    :: likeli_new !< likelihood using stddev_new,
+        real(dp)                           :: value      !< output value
+      end function likelihood_interface
+  end interface
+
+  !> \brief Optimizee for a eval-objective pair
+  type, extends(optimizee) :: eval_optimizee
+    procedure(eval_interface), pointer, nopass :: eval_pointer => null()  !< Pointer to the eval
+    procedure(objective_interface), pointer, nopass :: obj_pointer => null()  !< Pointer to the objective
+  contains
+    procedure :: evaluate => evaluate_obj_eval
+  end type eval_optimizee
+
+contains
+
+  !> \brief Implementation of the evaluate procedure for a simple function
+  function evaluate_function(self, parameters, sigma, stddev_new, likeli_new) result(value)
+      class(function_optimizee), intent(inout) :: self
+      real(dp), dimension(:), intent(in) :: parameters !< parameter set
+      real(dp), intent(in), optional     :: sigma      !< likelihood: standard deviation of data
+      real(dp), intent(out), optional    :: stddev_new !< likelihood: standard deviation of errors using parameters
+      real(dp), intent(out), optional    :: likeli_new !< likelihood: likelihood using stddev_new
+      real(dp)                           :: value      !< output value
+
+      ! Ensure the function pointer is set
+      if (.not. associated(self%func_pointer)) then
+          call error_message("Function pointer is not set in function_optimizee!")
+      end if
+
+      ! Check optional arguments
+      if (present(sigma) .or. present(stddev_new) .or. present(likeli_new)) then
+        call error_message("function_optimizee doesn't support 'sigma', 'stddev_new' or 'likeli_new'!")
+      end if
+
+      ! Call the function pointer
+      value = self%func_pointer(parameters)
+  end function evaluate_function
+
+  !> \brief Implementation of the evaluate procedure for a likelihood function
+  function evaluate_likelihood(self, parameters, sigma, stddev_new, likeli_new) result(value)
+    class(likelihood_optimizee), intent(inout) :: self
+    real(DP), dimension(:), intent(in) :: parameters
+    real(DP), intent(in),  optional :: sigma
+    real(DP), intent(out), optional :: stddev_new
+    real(DP), intent(out), optional :: likeli_new
+    real(DP) :: value
+
+    ! Ensure the likelihood function pointer is set
+    if (.not. associated(self%likelihood_pointer)) then
+        call error_message("Likelihood function pointer is not set in likelihood_optimizee!")
+    end if
+
+    ! Call the likelihood function pointer
+    value = self%likelihood_pointer(parameters, sigma, stddev_new, likeli_new)
+  end function evaluate_likelihood
+
+  !> \brief Implementation of the evaluate procedure for a eval-objective pair
+  function evaluate_obj_eval(self, parameters, sigma, stddev_new, likeli_new) result(value)
+    class(eval_optimizee), intent(inout) :: self
+    real(DP), dimension(:), intent(in) :: parameters
+    real(DP), intent(in),  optional :: sigma
+    real(DP), intent(out), optional :: stddev_new
+    real(DP), intent(out), optional :: likeli_new
+    real(DP) :: value
+
+    ! Ensure the eval function pointer is set
+    if (.not. associated(self%eval_pointer)) then
+      call error_message("Eval function pointer is not set in eval_optimizee!")
+    end if
+    ! Ensure the objective function pointer is set
+    if (.not. associated(self%obj_pointer)) then
+      call error_message("Objective function pointer is not set in eval_optimizee!")
+    end if
+
+    ! Call the objective function pointer
+    value = self%obj_pointer(parameters, self%eval_pointer, sigma, stddev_new, likeli_new)
+  end function evaluate_obj_eval
+
 end module mo_optimization_utils