diff --git a/compiler2/ttcn3/AST_ttcn3.cc b/compiler2/ttcn3/AST_ttcn3.cc
index 29b8dac0c857454a92248f840feb42994dbea368..723cba45e9394879bef0de188ffec925501122c7 100644
--- a/compiler2/ttcn3/AST_ttcn3.cc
+++ b/compiler2/ttcn3/AST_ttcn3.cc
@@ -7032,6 +7032,8 @@ namespace Ttcn {
         " in clause 16.1.4 of the TTCN-3 core language standard (ES 201 873-1)",
         id->get_dispname().c_str());
     }
+    ClassTypeBody* my_class = my_scope->get_scope_class();
+
     // `runs on' clause and `port' clause are mutually exclusive
     if (runs_on_ref && port_ref) {
       runs_on_ref->error("A `runs on' and a `port' clause cannot be present at the same time.");
@@ -7039,6 +7041,10 @@ namespace Ttcn {
     if (my_scope->is_class_scope()) {
       // class methods inherit `runs on', `mtc' and `system' clauses from the class
       ClassTypeBody* class_ = my_scope->get_scope_class();
+      if (class_->is_trait()) {
+        error("Trait class type `%s' cannot have non-abstract methods",
+          class_->get_my_def()->get_Type()->get_typename().c_str());
+      }
       runs_on_type = class_->get_RunsOnType();
       mtc_type = class_->get_MtcType();
       system_type = class_->get_SystemType();
@@ -7783,9 +7789,14 @@ namespace Ttcn {
     checked = true;
     Error_Context cntxt(this, "In external function definition `%s'",
       id->get_dispname().c_str());
-    if (!ext_keyword && !my_scope->get_scope_class()->is_external()) {
+    ClassTypeBody* my_class = my_scope->get_scope_class();
+    if (!ext_keyword && !my_class->is_external()) {
       error("Missing function body or `external' keyword");
     }
+    if (my_class != NULL && my_class->is_trait()) {
+      error("Trait class type `%s' cannot have non-abstract methods",
+        my_class->get_my_def()->get_Type()->get_typename().c_str());
+    }
     fp_list->chk(asstype);
     if (return_type) {
       Error_Context cntxt2(return_type, "In return type");
@@ -8401,7 +8412,7 @@ namespace Ttcn {
     if (my_class == NULL) {
       FATAL_ERROR("Def_AbsFunction::chk");
     }
-    if (!my_class->is_abstract()) {
+    if (!my_class->is_abstract() && !my_class->is_trait()) {
       error("Concrete class type `%s' cannot have abstract methods",
         my_class->get_my_def()->get_Type()->get_typename().c_str());
     }
diff --git a/compiler2/ttcn3/Ttcnstuff.cc b/compiler2/ttcn3/Ttcnstuff.cc
index 92d2d6d0aece807ec9badb01c80edccd423b1818..acf2ed00277388d5021587486569772e002a31d8 100644
--- a/compiler2/ttcn3/Ttcnstuff.cc
+++ b/compiler2/ttcn3/Ttcnstuff.cc
@@ -3067,11 +3067,11 @@ namespace Ttcn {
   // =================================
   
   ClassTypeBody::ClassTypeBody(Common::Identifier* p_class_id, boolean p_external, boolean p_final,
-                               boolean p_abstract, Common::Type* p_base_type,
+                               boolean p_abstract, boolean p_trait, Types* p_base_types,
                                Reference* p_runs_on_ref, Reference* p_mtc_ref, Reference* p_system_ref,
                                Definitions* p_members, StatementBlock* p_finally_block)
   : Scope(), Location(), class_id(p_class_id), my_def(NULL), external(p_external), final(p_final),
-    abstract(p_abstract), built_in(FALSE), base_type(p_base_type), base_class(NULL),
+    abstract(p_abstract), trait(p_trait), built_in(FALSE), base_type(NULL), base_traits(p_base_types), base_class(NULL),
     runs_on_ref(p_runs_on_ref), runs_on_type(NULL), mtc_ref(p_mtc_ref),
     mtc_type(NULL), system_ref(p_system_ref), system_type(NULL),
     members(p_members), finally_block(p_finally_block), constructor(NULL), checked(false),
@@ -3088,8 +3088,8 @@ namespace Ttcn {
   
   ClassTypeBody::ClassTypeBody()
   : Scope(), Location(), class_id(NULL), my_def(NULL), external(FALSE), final(FALSE),
-    abstract(TRUE), built_in(TRUE), base_type(NULL), base_class(NULL),
-    runs_on_ref(NULL), runs_on_type(NULL), mtc_ref(NULL),
+    abstract(TRUE), trait(FALSE), built_in(TRUE), base_type(NULL), base_class(NULL),
+    base_traits(NULL), runs_on_ref(NULL), runs_on_type(NULL), mtc_ref(NULL),
     mtc_type(NULL), system_ref(NULL), system_type(NULL),
     members(NULL), finally_block(NULL), constructor(NULL), checked(false),
     default_constructor(false)
@@ -3105,11 +3105,16 @@ namespace Ttcn {
     external = p.external;
     final = p.final;
     abstract = p.abstract;
+    trait = p.trait;
     base_type = p.base_type != NULL ? p.base_type->clone() : NULL;
     base_class = p.base_class;
+    base_traits = p.base_traits != NULL ? p.base_traits->clone() : NULL;
     runs_on_ref = p.runs_on_ref != NULL ? p.runs_on_ref->clone() : NULL;
+    runs_on_type = p.runs_on_type;
     mtc_ref = p.mtc_ref != NULL ? p.mtc_ref->clone() : NULL;
+    mtc_type = p.mtc_type;
     system_ref = p.system_ref != NULL ? p.system_ref->clone() : NULL;
+    system_type = p.system_type;
     members = p.members != NULL ? p.members->clone() : NULL;
     finally_block = p.finally_block != NULL ? p.finally_block->clone() : NULL;
     default_constructor = p.default_constructor;
@@ -3128,6 +3133,7 @@ namespace Ttcn {
       return;
     }
     delete base_type;
+    delete base_traits;
     delete finally_block;
     delete members;
     delete mtc_ref;
@@ -3156,6 +3162,9 @@ namespace Ttcn {
     if (base_type != NULL) {
       base_type->set_fullname(p_fullname + ".<superclass>");
     }
+    if (base_traits != NULL) {
+      base_traits->set_fullname(p_fullname + ".<supertraits>");
+    }
     if (runs_on_ref != NULL) {
       runs_on_ref->set_fullname(p_fullname + ".<runs_on_type>");
     }
@@ -3180,6 +3189,9 @@ namespace Ttcn {
     if (base_type != NULL) {
       base_type->set_my_scope(p_scope);
     }
+    if (base_traits != NULL) {
+      base_traits->set_my_scope(p_scope);
+    }
     if (runs_on_ref != NULL) {
       runs_on_ref->set_my_scope(p_scope);
     }
@@ -3203,8 +3215,18 @@ namespace Ttcn {
     }
     DEBUG(level, "Modifiers:%s%s%s", external ? "external " : "",
       final ? " @final " : "", abstract ? " @abstract" : "");
-    DEBUG(level, "Base class: %s", base_type != NULL ?
-      base_type->get_typename().c_str() : "");
+    DEBUG(level, "Base classes:");
+    if (base_type != NULL) {
+      DEBUG(level + 1, base_type->get_typename().c_str());
+    }
+    if (base_traits != NULL) {
+      for (size_t i = 0; i < base_traits->get_nof_types(); ++i) {
+        Type* base_trait = base_traits->get_type_byIndex(i);
+        if (base_trait != NULL) {
+          DEBUG(level + 1, base_trait->get_typename().c_str());
+        }
+      }
+    }
     if (runs_on_ref != NULL) {
       DEBUG(level, "Runs on clause:");
       runs_on_ref->dump(level + 1);
@@ -3268,13 +3290,22 @@ namespace Ttcn {
     if (!checked) {
       chk();
     }
-    if (this == p_class || p_class->built_in) {
+    if (this == p_class || (!trait && p_class->built_in)) {
       return true;
     }
-    if (base_class == NULL) {
-      return false;
+    if (base_class != NULL && base_class->is_parent_class(p_class)) {
+      return true;
+    }
+    if (base_traits != NULL) {
+      for (size_t i = 0; i < base_traits->get_nof_types(); ++i) {
+        Type* base_trait = base_traits->get_type_byIndex(i);
+        if (base_trait != NULL &&
+            base_trait->get_type_refd_last()->get_class_type_body()->is_parent_class(p_class)) {
+          return true;
+        }
+      }
     }
-    return base_class->is_parent_class(p_class);
+    return false;
   }
   
   bool ClassTypeBody::has_local_ass_withId(const Identifier& p_id)
@@ -3288,12 +3319,19 @@ namespace Ttcn {
     if (members->has_local_ass_withId(p_id)) {
       return true;
     }
-    if (base_class != NULL) {
-      return base_class->has_local_ass_withId(p_id);
+    if (base_class != NULL && base_class->has_local_ass_withId(p_id)) {
+      return true;
     }
-    else {
-      return false;
+    if (base_traits) {
+      for (size_t i = 0; i < base_traits->get_nof_types(); ++i) {
+        Type* base_trait = base_traits->get_type_byIndex(i);
+        if (base_trait != NULL &&
+            base_trait->get_type_refd_last()->get_class_type_body()->has_local_ass_withId(p_id)) {
+          return true;
+        }
+      }
     }
+    return false;
   }
   
   Common::Assignment* ClassTypeBody::get_local_ass_byId(const Identifier& p_id)
@@ -3311,6 +3349,17 @@ namespace Ttcn {
     if (ass == NULL && base_class != NULL) {
       ass = base_class->get_local_ass_byId(p_id);
     }
+    if (ass == NULL && base_traits != NULL) {
+      for (size_t i = 0; i < base_traits->get_nof_types(); ++i) {
+        Type* base_trait = base_traits->get_type_byIndex(i);
+        if (base_trait != NULL) {
+          ass = base_trait->get_type_refd_last()->get_class_type_body()->get_local_ass_byId(p_id);
+          if (ass != NULL) {
+            break;
+          }
+        }
+      }
+    }
     return ass;
   }
   
@@ -3347,7 +3396,7 @@ namespace Ttcn {
       ass->get_id().get_dispname().c_str(), class_id->get_dispname().c_str());
     return false;
   }
-  
+
   Common::Assignment* ClassTypeBody::get_ass_bySRef(Common::Ref_simple* p_ref)
   {
     if (built_in) {
@@ -3379,13 +3428,13 @@ namespace Ttcn {
         // nothing special is needed for 'this.field' or 'this.method'
         // (it's already been handled at the lower scopes)
       }
-      
+
       if (id != NULL && has_local_ass_withId(*id)) {
         Common::Assignment* ass = get_local_ass_byId(*id);
         if (ass == NULL) {
           FATAL_ERROR("ClassTypeBody::get_ass_bySRef()");
         }
-        
+
         if (chk_visibility(ass, p_ref, p_ref->get_my_scope())) {
           return ass;
         }
@@ -3397,39 +3446,178 @@ namespace Ttcn {
     return parent_scope->get_ass_bySRef(p_ref);
   }
   
+  bool ClassTypeBody::compare_members(ClassTypeBody* c1, ClassTypeBody* c2, Location* subclass_loc)
+  {
+    // if subclass_loc is NULL, then c1 is the subclass and c2 is the base class or a base trait
+    // otherwise both c1 and c2 are inherited by the subclass
+    if (subclass_loc != NULL && (c1->is_parent_class(c2) || c2->is_parent_class(c1))) {
+      return false;
+    }
+    bool name_clash = false;
+    for (size_t i = 0; i < c1->members->get_nof_asss(); ++i) {
+      Common::Assignment* def1 = c1->members->get_ass_byIndex(i, false);
+      if (def1->get_asstype() == Common::Assignment::A_CONSTRUCTOR) {
+        continue;
+      }
+      const Common::Identifier& id1 = def1->get_id();
+      if (c2->has_local_ass_withId(id1)) {
+        Common::Assignment* def2 = c2->get_local_ass_byId(id1);
+        ClassTypeBody* def2_class = def2->get_my_scope()->get_scope_class();
+        if (subclass_loc != NULL &&
+            def2_class != c2 && def2_class != c1 && c1->is_parent_class(def2_class)) {
+          // def2 is defined in a trait class that is inherited by both c1 and c2,
+          // ignore this comparison
+          continue;
+        }
+        switch (def1->get_asstype()) {
+        case Common::Assignment::A_FUNCTION:
+        case Common::Assignment::A_FUNCTION_RVAL:
+        case Common::Assignment::A_FUNCTION_RTEMP:
+        case Common::Assignment::A_EXT_FUNCTION:
+        case Common::Assignment::A_EXT_FUNCTION_RVAL:
+        case Common::Assignment::A_EXT_FUNCTION_RTEMP:
+          switch (def2->get_asstype()) {
+          case Common::Assignment::A_FUNCTION:
+          case Common::Assignment::A_FUNCTION_RVAL:
+          case Common::Assignment::A_FUNCTION_RTEMP:
+          case Common::Assignment::A_EXT_FUNCTION:
+          case Common::Assignment::A_EXT_FUNCTION_RVAL:
+          case Common::Assignment::A_EXT_FUNCTION_RTEMP: {
+            Def_Function_Base* func1 = dynamic_cast<Def_Function_Base*>(def1);
+            Def_Function_Base* func2 = dynamic_cast<Def_Function_Base*>(def2);
+            bool func1_is_abstract = dynamic_cast<Def_AbsFunction*>(func1) != NULL;
+            bool func2_is_abstract = dynamic_cast<Def_AbsFunction*>(func2) != NULL;
+            bool functions_are_identical = func1->is_identical(func2);
+            if (func2->get_visibility() != PRIVATE &&
+                (!functions_are_identical || func1_is_abstract != func2_is_abstract)) {
+              if (subclass_loc == NULL && !functions_are_identical) {
+                def1->error("The prototype of method `%s' is not identical "
+                  "to that of inherited method `%s'",
+                  id1.get_dispname().c_str(), def2->get_fullname().c_str());
+              }
+              else if (subclass_loc != NULL && func1->get_visibility() != PRIVATE) {
+                subclass_loc->error("The prototypes of methods `%s' inherited from "
+                  "classes `%s' and `%s' are not identical",
+                  id1.get_dispname().c_str(), c1->get_id()->get_dispname().c_str(),
+                  c2->get_id()->get_dispname().c_str());
+              }
+            }
+            else if (subclass_loc == NULL && func2->is_final()) {
+              def1->error("Cannot override final method `%s'",
+                def2->get_fullname().c_str());
+            }
+            else if (subclass_loc == NULL && func1->is_identical(func2)) {
+              if (func2->get_visibility() == PUBLIC && func1->get_visibility() != PUBLIC) {
+                def1->error("Public methods can be only overridden by public methods `%s'",
+                  id1.get_dispname().c_str());
+              }
+              else if (func2->get_visibility() == NOCHANGE &&
+                       func1->get_visibility() != PUBLIC && func1->get_visibility() != NOCHANGE) {
+                def1->error("Protected methods can be only overridden by "
+                  "public or protected methods `%s'", id1.get_dispname().c_str());
+              }
+            }
+            break; }
+          default:
+            def1->error("%s shadows inherited member `%s'",
+              def1->get_description().c_str(), def2->get_fullname().c_str());
+            name_clash = true;
+            break;
+          }
+          break;
+        default:
+          def1->error("%s shadows inherited %s `%s'",
+            def1->get_description().c_str(),
+            dynamic_cast<Def_Function_Base*>(def2) != NULL ? "method" : "member",
+            def2->get_fullname().c_str());
+          name_clash = true;
+          break;
+        }
+      }
+    }
+    if (subclass_loc != NULL) {
+      // the code above only goes through the local members of c1,
+      // comparing them to local or inherited members of c2;
+      // the members in the superclass and supertraits of c1 must also be compared to c2
+      if (c1->base_class != NULL) {
+        name_clash |= compare_members(c1->base_class, c2, subclass_loc);
+      }
+      if (c1->base_traits != NULL) {
+        for (size_t i = 0; i < c1->base_traits->get_nof_types(); ++i) {
+          Type* base_trait = c1->base_traits->get_type_byIndex(i);
+          if (base_trait != NULL) {
+            ClassTypeBody* base_trait_class = base_trait->get_type_refd_last()->get_class_type_body();
+            name_clash |= compare_members(base_trait_class, c2, subclass_loc);
+          }
+        }
+      }
+    }
+    return name_clash;
+  }
+  
   void ClassTypeBody::chk()
   {
     if (checked || built_in) {
       return;
     }
     checked = true;
-    if (final && abstract) {
-      error("Final classes cannot be abstract");
+    if ((final && abstract) || (final && trait) || (abstract && trait)) {
+      error("A classes cannot have more than one of the @final, @abstract and @trait modifiers");
     }
-    if (external && abstract) {
+    if (external && abstract) { // todo
       error("External classes cannot be abstract");
     }
-    if (base_type != NULL) {
-      Error_Context cntxt(base_type, "In superclass definition");
-      base_type->chk();
-      if (base_type->get_type_refd_last()->get_typetype() != Common::Type::T_CLASS) {
-        if (base_type->get_typetype() != Common::Type::T_ERROR) {
-          base_type->error("Class type expected instead of `%s'",
-            base_type->get_typename().c_str());
-        }
-        delete base_type;
-        base_type = NULL;
-      }
-      else {
-        base_class = base_type->get_type_refd_last()->get_class_type_body();
-        if (base_class->final) {
-          base_type->error("The superclass cannot be final");
+    if (base_traits != NULL) {
+      for (size_t i = 0; i < base_traits->get_nof_types(); ++i) {
+        Type* t = base_traits->get_type_byIndex(i);
+        Error_Context cntxt(t, "In superclass or supertrait definition");
+        t->chk();
+        if (t->get_type_refd_last()->get_typetype() != Common::Type::T_CLASS) {
+          if (t->get_typetype() != Common::Type::T_ERROR) {
+            t->error("Class type expected instead of `%s'", t->get_typename().c_str());
+          }
+          base_traits->extract_type_byIndex(i);
+          delete t;
         }
-        if (external && !base_class->external) {
-          base_type->error("An external class cannot extend an internal class");
+        else {
+          ClassTypeBody* t_class = t->get_type_refd_last()->get_class_type_body();
+          if (!t_class->trait) {
+            if (trait) {
+              t->error("A trait class cannot extend a non-trait class");
+            }
+            else if (base_type != NULL) {
+              t->error("A class cannot extend more than one non-trait class");
+              base_type->note("Previous extended non-trait class is here");
+            }
+            else {
+              base_traits->extract_type_byIndex(i);
+              base_type = t;
+              base_class = t_class;
+              if (base_class->final) {
+                base_type->error("The superclass cannot be final");
+              }
+              if (external && !base_class->external) {
+                base_type->error("An external class cannot extend an internal class");
+              }
+            }
+          }
+          for (size_t j = 0; j < i; ++j) {
+            Type* t2 = base_traits->get_type_byIndex(j);
+            if (t2 != NULL && t2->get_typename() == t->get_typename()) {
+              t->error("Duplicate class type in list of classes being extended");
+              t2->note("Class type `%s' is already given here", t->get_typename().c_str());
+            }
+          }
         }
       }
     }
+    if (base_class != NULL && base_class->built_in) {
+      // if the base class is 'object', then just delete it and set it to NULL,
+      // so it functions the same way as not specifying a base class
+      delete base_type;
+      base_type = NULL;
+      base_class = NULL;
+    }
     
     if (runs_on_ref != NULL) {
       Error_Context cntxt(runs_on_ref, "In `runs on' clause");
@@ -3489,6 +3677,64 @@ namespace Ttcn {
       system_type = base_class->get_SystemType();
     }
     
+    if (base_traits != NULL) {
+      for (size_t i = 0; i < base_traits->get_nof_types(); ++i) {
+        Type* base_trait = base_traits->get_type_byIndex(i);
+        if (base_trait != NULL) {
+          ClassTypeBody* base_trait_class = base_trait->get_type_refd_last()->
+            get_class_type_body();
+          Type* base_runs_on_type = base_trait_class->get_RunsOnType();
+          if (base_runs_on_type != NULL) {
+            if (runs_on_type == NULL) {
+              error("Supertrait `%s' has a `runs on` component type, "
+                "but the subclass and its superclass does not",
+                base_trait_class->class_id->get_dispname().c_str());
+            }
+            else if(!base_runs_on_type->is_compatible(runs_on_type, NULL, NULL)) {
+              runs_on_ref->error("The `runs on' component type of the subclass "
+                "(`%s') is not compatible with the `runs on' component type of "
+                "supertrait `%s' (`%s')",
+                runs_on_type->get_typename().c_str(),
+                base_trait_class->class_id->get_dispname().c_str(),
+                base_runs_on_type->get_typename().c_str());
+            }
+          }
+          Type* base_mtc_type = base_trait_class->get_MtcType();
+          if (base_mtc_type != NULL) {
+            if (mtc_type == NULL) {
+              error("Supertrait `%s' has an `mtc` component type, "
+                "but the subclass and its superclass does not",
+                base_trait_class->class_id->get_dispname().c_str());
+            }
+            else if(!base_mtc_type->is_compatible(mtc_type, NULL, NULL)) {
+              mtc_ref->error("The `mtc' component type of the subclass "
+                "(`%s') is not compatible with the `mtc' component type of "
+                "supertrait `%s' (`%s')",
+                mtc_type->get_typename().c_str(),
+                base_trait_class->class_id->get_dispname().c_str(),
+                base_mtc_type->get_typename().c_str());
+            }
+          }
+          Type* base_system_type = base_trait_class->get_SystemType();
+          if (base_system_type != NULL) {
+            if (system_type == NULL) {
+              error("Supertrait `%s' has an `system` component type, "
+                "but the subclass and its superclass does not",
+                base_trait_class->class_id->get_dispname().c_str());
+            }
+            else if(!base_system_type->is_compatible(system_type, NULL, NULL)) {
+              system_ref->error("The `system' component type of the subclass "
+                "(`%s') is not compatible with the `system' component type of "
+                "supertrait `%s' (`%s')",
+                system_type->get_typename().c_str(),
+                base_trait_class->class_id->get_dispname().c_str(),
+                base_system_type->get_typename().c_str());
+            }
+          }
+        }
+      }
+    }
+
     for (size_t i = 0; i < members->get_nof_asss(); ++i) {
       Common::Assignment* ass = members->get_ass_byIndex(i, false);
       if (ass->get_asstype() == Common::Assignment::A_CONSTRUCTOR) {
@@ -3519,68 +3765,10 @@ namespace Ttcn {
       }
     }
 
-    bool name_clash = false;
-    if (base_class != NULL || runs_on_type != NULL || mtc_type != NULL || system_type != NULL) {
+    if (runs_on_type != NULL || mtc_type != NULL || system_type != NULL) {
       for (size_t i = 0; i < members->get_nof_asss(); ++i) {
         Common::Assignment* local_def = members->get_ass_byIndex(i, false);
         const Common::Identifier& local_id = local_def->get_id();
-        if (base_class != NULL &&
-            local_def->get_asstype() != Common::Assignment::A_CONSTRUCTOR &&
-            base_class->has_local_ass_withId(local_id)) {
-          Common::Assignment* base_def = base_class->get_local_ass_byId(local_id);
-          switch (local_def->get_asstype()) {
-          case Common::Assignment::A_FUNCTION:
-          case Common::Assignment::A_FUNCTION_RVAL:
-          case Common::Assignment::A_FUNCTION_RTEMP:
-          case Common::Assignment::A_EXT_FUNCTION:
-          case Common::Assignment::A_EXT_FUNCTION_RVAL:
-          case Common::Assignment::A_EXT_FUNCTION_RTEMP:
-            switch (base_def->get_asstype()) {
-            case Common::Assignment::A_FUNCTION:
-            case Common::Assignment::A_FUNCTION_RVAL:
-            case Common::Assignment::A_FUNCTION_RTEMP:
-            case Common::Assignment::A_EXT_FUNCTION:
-            case Common::Assignment::A_EXT_FUNCTION_RVAL:
-            case Common::Assignment::A_EXT_FUNCTION_RTEMP: {
-              Def_Function_Base* local_func = dynamic_cast<Def_Function_Base*>(local_def);
-              Def_Function_Base* base_func = dynamic_cast<Def_Function_Base*>(base_def);
-              if (base_func->get_visibility() != PRIVATE && !local_func->is_identical(base_func)) {
-                local_def->error("The prototype of method `%s' is not identical "
-                  "to that of inherited method `%s'",
-                  local_id.get_dispname().c_str(), base_def->get_fullname().c_str());
-              }
-              else if (base_func->is_final()) {
-                local_def->error("Cannot override final method `%s'",
-                  base_def->get_fullname().c_str());
-              }
-              else if (local_func->is_identical(base_func)) {
-            	  if (base_func->get_visibility() == PUBLIC && local_func->get_visibility() != PUBLIC) {
-            		  local_def->error("Public methods can be only overridden by public methods `%s'",
-            		    local_id.get_dispname().c_str());
-            	  }
-            	  else if (base_func->get_visibility() == NOCHANGE &&
-            			   local_func->get_visibility() != PUBLIC && local_func->get_visibility() != NOCHANGE) {
-            		  local_def->error("Protected methods can be only overridden by "
-            		    "public or protected methods `%s'", local_id.get_dispname().c_str());
-            	  }
-              }
-              break; }
-            default:
-              local_def->error("%s shadows inherited member `%s'",
-                local_def->get_description().c_str(), base_def->get_fullname().c_str());
-              name_clash = true;
-              break;
-            }
-            break;
-          default:
-            local_def->error("%s shadows inherited %s `%s'",
-              local_def->get_description().c_str(),
-              dynamic_cast<Def_Function_Base*>(base_def) != NULL ? "method" : "member",
-              base_def->get_fullname().c_str());
-            name_clash = true;
-            break;
-          }
-        }
         if (runs_on_type != NULL && runs_on_type->get_CompBody()->has_local_ass_withId(local_id)) {
           local_def->error("%s shadows a definition in runs-on component type `%s'",
             local_def->get_description().c_str(), runs_on_type->get_typename().c_str());
@@ -3596,7 +3784,37 @@ namespace Ttcn {
       }
     }
     
-    if (constructor == NULL && !name_clash) {
+    bool name_clash = false;
+    if (base_class != NULL) {
+      name_clash = compare_members(this, base_class);
+    }
+    if (base_traits != NULL) {
+      for (size_t i = 0; i < base_traits->get_nof_types(); ++i) {
+        Type* base_trait = base_traits->get_type_byIndex(i);
+        if (base_trait != NULL) {
+          ClassTypeBody* base_trait_class = base_trait->get_type_refd_last()->
+            get_class_type_body();
+          name_clash |= compare_members(this, base_trait_class);
+          if (base_class != NULL) {
+            name_clash |= compare_members(base_class, base_trait_class, this);
+          }
+          for (size_t j = 0; j < i; ++j) {
+            Type* base_trait2 = base_traits->get_type_byIndex(j);
+            if (base_trait2 != NULL) {
+              ClassTypeBody* base_trait_class2 = base_trait2->get_type_refd_last()->
+                get_class_type_body();
+              name_clash |= compare_members(base_trait_class, base_trait_class2, this);
+            }
+          }
+        }
+      }
+    }
+
+    if (constructor != NULL && trait) {
+      constructor->error("Trait class type `%s' cannot have a constructor",
+        my_def->get_Type()->get_typename().c_str());
+    }
+    if (constructor == NULL && !name_clash && !trait) {
       // create a default constructor
       Reference* base_call = NULL;
       FormalParList* fp_list = NULL;
@@ -3668,6 +3886,10 @@ namespace Ttcn {
     if (finally_block != NULL) {
       Error_Context cntxt(finally_block, "In class destructor");
       finally_block->chk();
+      if (trait) {
+        finally_block->error("Trait class type `%s' cannot have a destructor",
+          my_def->get_Type()->get_typename().c_str());
+      }
     }
     
     if (external) {
@@ -3690,7 +3912,7 @@ namespace Ttcn {
       }
     }
     
-    if (abstract) {
+    if (abstract || trait) {
       // create a map of all abstract functions (including inherited ones)
       if (base_class != NULL && base_class->abstract) {
         for (size_t i = 0; i < base_class->abstract_functions.size(); ++i) {
@@ -3698,6 +3920,21 @@ namespace Ttcn {
             base_class->abstract_functions.get_nth_elem(i));
         }
       }
+      if (base_traits != NULL) {
+        for (size_t i = 0; i < base_traits->get_nof_types(); ++i) {
+          Type* base_trait = base_traits->get_type_byIndex(i);
+          if (base_trait != NULL) {
+            ClassTypeBody* base_trait_class = base_trait->get_type_refd_last()->
+              get_class_type_body();
+            for (size_t j = 0; j < base_trait_class->abstract_functions.size(); ++j) {
+              const string& key = base_trait_class->abstract_functions.get_nth_key(j);
+              if (!abstract_functions.has_key(key)) {
+                abstract_functions.add(key, base_trait_class->abstract_functions.get_nth_elem(j));
+              }
+            }
+          }
+        }
+      }
       for (size_t i = 0; i < members->get_nof_asss(); ++i) {
         Common::Assignment* ass = members->get_ass_byIndex(i, false);
         switch (ass->get_asstype()) {
@@ -3718,26 +3955,57 @@ namespace Ttcn {
       }
     }
     
-    if (!abstract && base_class != NULL && base_class->abstract) {
-      // all abstract methods from the base class have to be implemented in this class
-      for (size_t i = 0; i < base_class->abstract_functions.size(); ++i) {
-        Def_AbsFunction* def_abs_func = base_class->abstract_functions.get_nth_elem(i);
-        Common::Assignment* ass = get_local_ass_byId(def_abs_func->get_id());
-        switch (ass->get_asstype()) {
-        case Common::Assignment::A_FUNCTION:
-        case Common::Assignment::A_FUNCTION_RVAL:
-        case Common::Assignment::A_FUNCTION_RTEMP: {
-          if (dynamic_cast<Def_AbsFunction*>(ass) != NULL) {
-            error("Missing implementation of abstract method `%s'",
-              def_abs_func->get_fullname().c_str());
+    if (!abstract && !trait) {
+      // all abstract methods from the base class and base traits have to be implemented in this class
+      if (base_class != NULL && base_class->abstract) {
+        for (size_t i = 0; i < base_class->abstract_functions.size(); ++i) {
+          Def_AbsFunction* def_abs_func = base_class->abstract_functions.get_nth_elem(i);
+          Common::Assignment* ass = get_local_ass_byId(def_abs_func->get_id());
+          switch (ass->get_asstype()) {
+          case Common::Assignment::A_FUNCTION:
+          case Common::Assignment::A_FUNCTION_RVAL:
+          case Common::Assignment::A_FUNCTION_RTEMP: {
+            if (dynamic_cast<Def_AbsFunction*>(ass) != NULL) {
+              error("Missing implementation of abstract method `%s'",
+                def_abs_func->get_fullname().c_str());
+            }
+            // whether the new function is identical to the abstract one has
+            // already been checked
+            break; }
+          default:
+            // it's either an external function (which is OK), or
+            // it's shadowed by a member (error has already been reported)
+            break;
+          }
+        }
+      }
+      if (base_traits != NULL) {
+        for (size_t k = 0; k < base_traits->get_nof_types(); ++k) {
+          Type* base_trait = base_traits->get_type_byIndex(k);
+          if (base_trait != NULL) {
+            ClassTypeBody* base_trait_class = base_trait->get_type_refd_last()->
+              get_class_type_body();
+            for (size_t i = 0; i < base_trait_class->abstract_functions.size(); ++i) {
+              Def_AbsFunction* def_abs_func = base_trait_class->abstract_functions.get_nth_elem(i);
+              Common::Assignment* ass = get_local_ass_byId(def_abs_func->get_id());
+              switch (ass->get_asstype()) {
+              case Common::Assignment::A_FUNCTION:
+              case Common::Assignment::A_FUNCTION_RVAL:
+              case Common::Assignment::A_FUNCTION_RTEMP: {
+                if (dynamic_cast<Def_AbsFunction*>(ass) != NULL) {
+                  error("Missing implementation of abstract method `%s'",
+                    def_abs_func->get_fullname().c_str());
+                }
+                // whether the new function is identical to the abstract one has
+                // already been checked
+                break; }
+              default:
+                // it's either an external function (which is OK), or
+                // it's shadowed by a member (error has already been reported)
+                break;
+              }
+            }
           }
-          // whether the new function is identical to the abstract one has
-          // already been checked
-          break; }
-        default:
-          // it's either an external function (which is OK), or
-          // it's shadowed by a member (error has already been reported)
-          break;
         }
       }
     }
@@ -3749,7 +4017,19 @@ namespace Ttcn {
       return;
     }
     if (base_type != NULL) {
+      refch.mark_state();
       base_type->chk_recursions(refch);
+      refch.prev_state();
+    }
+    if (base_traits != NULL) {
+      for (size_t i = 0; i < base_traits->get_nof_types(); ++i) {
+        Type* base_trait = base_traits->get_type_byIndex(i);
+        if (base_trait != NULL) {
+          refch.mark_state();
+          base_trait->chk_recursions(refch);
+          refch.prev_state();
+        }
+      }
     }
     
     for (size_t i = 0; i < members->get_nof_asss(); ++i) {
@@ -3763,7 +4043,9 @@ namespace Ttcn {
       case Common::Assignment::A_CONST:
       case Common::Assignment::A_TEMPLATE:
       case Common::Assignment::A_VAR_TEMPLATE:
+        refch.mark_state();
         def->get_Type()->chk_recursions(refch);
+        refch.prev_state();
         break;
       default:
         break;
@@ -3780,7 +4062,8 @@ namespace Ttcn {
       "class %s;\n", class_id->get_name().c_str());
     if (!external || generate_skeleton) {
       string base_type_name = base_type != NULL ?
-        base_type->get_type_refd_last()->get_genname_own(this) : string("OBJECT");
+        base_type->get_type_refd_last()->get_genname_own(this) :
+        trait ? string("CLASS_BASE") : string("OBJECT");
       output_struct* local_struct;
       if (external) {
         local_struct = new output_struct;
@@ -3791,8 +4074,27 @@ namespace Ttcn {
       }
       
       local_struct->header.class_defs = mputprintf(local_struct->header.class_defs,
-        "class %s : public %s {\n",
-        class_id->get_name().c_str(), base_type_name.c_str());
+        "class %s : ",
+        class_id->get_name().c_str());
+      bool has_base = false;
+      if (base_traits != NULL) {
+        for (size_t i = 0; i < base_traits->get_nof_types(); ++i) {
+          Type* base_trait = base_traits->get_type_byIndex(i);
+          if (base_trait != NULL) {
+            local_struct->header.class_defs = mputprintf(local_struct->header.class_defs,
+              "%spublic %s", has_base ? ", " : "",
+              base_trait->get_type_refd_last()->get_genname_own(this).c_str());
+            has_base = true;
+          }
+        }
+      }
+      if (!trait || !has_base) {
+        local_struct->header.class_defs = mputprintf(local_struct->header.class_defs,
+          "%s public %s", has_base ? ", " : "", base_type_name.c_str());
+        has_base |= base_type != NULL;
+      }
+      local_struct->header.class_defs = mputstr(local_struct->header.class_defs,
+        " {\n");
       
       // class name
       local_struct->header.class_defs = mputprintf(local_struct->header.class_defs,
@@ -3809,58 +4111,60 @@ namespace Ttcn {
       }
       
       // constructor
-      char* formal_par_list_str = NULL;
-      expression_struct_t base_call_expr;
-      Code::init_expr(&base_call_expr);
-      Reference* base_call = constructor->get_base_call();
-      if (base_call != NULL) {
-        base_call->generate_code(&base_call_expr);
-      }
-      // generate code for the base call first, so the formal parameter list
-      // knows which parameters are used and which aren't
-      formal_par_list_str = constructor->get_FormalParList()->generate_code(
-        memptystr(), external ? constructor->get_FormalParList()->get_nof_fps() : 0);
-      if (base_call_expr.expr == NULL) {
-        base_call_expr.expr = mprintf("%s()", base_type_name.c_str());
-      }
-      local_struct->header.class_defs = mputprintf(local_struct->header.class_defs,
-        "\npublic:\n%s"
-        "%s(%s);\n\n",
-        default_constructor ? "/* default constructor */\n" : "",
-        class_id->get_name().c_str(),
-        formal_par_list_str != NULL ? formal_par_list_str : "");
-      local_struct->source.methods = mputprintf(local_struct->source.methods,
-        "%s::%s(%s)\n"
-        ": %s",
-        class_id->get_name().c_str(), class_id->get_name().c_str(),
-        formal_par_list_str != NULL ? formal_par_list_str : "",
-        base_call_expr.expr);
-      Free(formal_par_list_str);
-      Code::free_expr(&base_call_expr);
-      if (local_struct->temp.constructor_init != NULL) {
-        local_struct->source.methods = mputstr(local_struct->source.methods,
-          local_struct->temp.constructor_init);
-        Free(local_struct->temp.constructor_init);
-        local_struct->temp.constructor_init = NULL;
-      }
-      local_struct->source.methods = mputstr(local_struct->source.methods, "\n{\n");
-      if (local_struct->temp.constructor_preamble != NULL ||
-          local_struct->temp.constructor_block != NULL) {
-        local_struct->source.methods = create_location_object(
-          local_struct->source.methods, "FUNCTION", class_id->get_name().c_str());
-        local_struct->source.methods = mputstr(local_struct->source.methods,
-          local_struct->temp.constructor_preamble);
-        local_struct->source.methods = mputstr(local_struct->source.methods,
-          local_struct->temp.constructor_block);
-        Free(local_struct->temp.constructor_preamble);
-        Free(local_struct->temp.constructor_block);
-        local_struct->temp.constructor_preamble = NULL;
-        local_struct->temp.constructor_block = NULL;
-      }
-      else if (external) {
-        local_struct->source.methods = mputc(local_struct->source.methods, '\n');
+      if (constructor != NULL) {
+        char* formal_par_list_str = NULL;
+        expression_struct_t base_call_expr;
+        Code::init_expr(&base_call_expr);
+        Reference* base_call = constructor->get_base_call();
+        if (base_call != NULL) {
+          base_call->generate_code(&base_call_expr);
+        }
+        // generate code for the base call first, so the formal parameter list
+        // knows which parameters are used and which aren't
+        formal_par_list_str = constructor->get_FormalParList()->generate_code(
+          memptystr(), external ? constructor->get_FormalParList()->get_nof_fps() : 0);
+        if (base_call_expr.expr == NULL) {
+          base_call_expr.expr = mprintf("%s()", base_type_name.c_str());
+        }
+        local_struct->header.class_defs = mputprintf(local_struct->header.class_defs,
+          "\npublic:\n%s"
+          "%s(%s);\n\n",
+          default_constructor ? "/* default constructor */\n" : "",
+          class_id->get_name().c_str(),
+          formal_par_list_str != NULL ? formal_par_list_str : "");
+        local_struct->source.methods = mputprintf(local_struct->source.methods,
+          "%s::%s(%s)\n"
+          ": %s",
+          class_id->get_name().c_str(), class_id->get_name().c_str(),
+          formal_par_list_str != NULL ? formal_par_list_str : "",
+          base_call_expr.expr);
+        Free(formal_par_list_str);
+        Code::free_expr(&base_call_expr);
+        if (local_struct->temp.constructor_init != NULL) {
+          local_struct->source.methods = mputstr(local_struct->source.methods,
+            local_struct->temp.constructor_init);
+          Free(local_struct->temp.constructor_init);
+          local_struct->temp.constructor_init = NULL;
+        }
+        local_struct->source.methods = mputstr(local_struct->source.methods, "\n{\n");
+        if (local_struct->temp.constructor_preamble != NULL ||
+            local_struct->temp.constructor_block != NULL) {
+          local_struct->source.methods = create_location_object(
+            local_struct->source.methods, "FUNCTION", class_id->get_name().c_str());
+          local_struct->source.methods = mputstr(local_struct->source.methods,
+            local_struct->temp.constructor_preamble);
+          local_struct->source.methods = mputstr(local_struct->source.methods,
+            local_struct->temp.constructor_block);
+          Free(local_struct->temp.constructor_preamble);
+          Free(local_struct->temp.constructor_block);
+          local_struct->temp.constructor_preamble = NULL;
+          local_struct->temp.constructor_block = NULL;
+        }
+        else if (external) {
+          local_struct->source.methods = mputc(local_struct->source.methods, '\n');
+        }
+        local_struct->source.methods = mputstr(local_struct->source.methods, "}\n\n");
       }
-      local_struct->source.methods = mputstr(local_struct->source.methods, "}\n\n");
 
       // destructor
       bool desctructor_body = finally_block != NULL || external;
@@ -3906,12 +4210,27 @@ namespace Ttcn {
         "void %s::log() const\n"
         "{\n"
         "TTCN_Logger::log_event_str(\"%s%s\");\n",
-        class_id->get_name().c_str(), class_id->get_dispname().c_str(), base_type != NULL ? " ( " : "");
+        class_id->get_name().c_str(), class_id->get_dispname().c_str(), has_base ? " ( " : "");
       if (base_type != NULL) {
         local_struct->source.methods = mputprintf(local_struct->source.methods,
-          "%s::log();\n"
-          "TTCN_Logger::log_event_str(\" )\");\n",
-          base_type_name.c_str());
+          "%s::log();\n", base_type_name.c_str());
+      }
+      if (base_traits != NULL) {
+        for (size_t i = 0; i < base_traits->get_nof_types(); ++i) {
+          Type* base_trait = base_traits->get_type_byIndex(i);
+          if (base_trait != NULL) {
+            if (i > 0 || base_type != NULL) {
+              local_struct->source.methods = mputstr(local_struct->source.methods,
+                "TTCN_Logger::log_event_str(\", \");\n");
+            }
+            local_struct->source.methods = mputprintf(local_struct->source.methods,
+              "%s::log();\n", base_trait->get_type_refd_last()->get_genname_own(this).c_str());
+          }
+        }
+      }
+      if (has_base) {
+        local_struct->source.methods = mputstr(local_struct->source.methods,
+          "TTCN_Logger::log_event_str(\" )\");\n");
       }
       local_struct->source.methods = mputstr(local_struct->source.methods,
         "}\n\n");
diff --git a/compiler2/ttcn3/Ttcnstuff.hh b/compiler2/ttcn3/Ttcnstuff.hh
index 78a4bdeba6ed28544f42568c8cb35abd2078acd9..0e44d94ca329f20536f8e483f54382aa98ccc7c2 100644
--- a/compiler2/ttcn3/Ttcnstuff.hh
+++ b/compiler2/ttcn3/Ttcnstuff.hh
@@ -285,7 +285,7 @@ public:
 };
 
 /**
- * Type list, used in port types
+ * Type list, used in port and class types
  */
 class Types : public Common::Node, public Common::Location {
 private:
@@ -763,9 +763,11 @@ class ClassTypeBody : public Common::Scope, public Common::Location {
   boolean external;
   boolean final;
   boolean abstract;
+  boolean trait;
   boolean built_in;
   Common::Type* base_type;
   ClassTypeBody* base_class; // not owned
+  Types* base_traits;
   Reference* runs_on_ref;
   Type* runs_on_type;
   Reference* mtc_ref;
@@ -783,7 +785,7 @@ class ClassTypeBody : public Common::Scope, public Common::Location {
   
 public:
   ClassTypeBody(Common::Identifier* p_class_id, boolean p_external, boolean p_final,
-    boolean p_abstract, Common::Type* p_base_type,
+    boolean p_abstract, boolean p_trait, Types* p_base_types,
     Ttcn::Reference* p_runs_on_ref, Reference* p_mtc_ref, Reference* p_system_ref,
     Definitions* p_members, StatementBlock* p_finally_block);
   ClassTypeBody();
@@ -794,6 +796,7 @@ public:
   void set_my_def(Def_Type* p_def);
   Def_Type* get_my_def() { return my_def; }
   boolean is_abstract() const { return abstract; }
+  boolean is_trait() const { return trait; }
   boolean is_external() const { return external; }
   
   void set_fullname(const string& p_fullname);
@@ -817,6 +820,7 @@ public:
   Common::Assignment* get_local_ass_byId(const Identifier& p_id);
   Common::Assignment* get_ass_bySRef(Common::Ref_simple* p_ref);
   
+  static bool compare_members(ClassTypeBody* c1, ClassTypeBody* c2, Location* subclass_loc = NULL);
   bool chk_visibility(Common::Assignment* ass, Common::Location* usage_loc,
     Common::Scope* usage_scope);
   void chk();
diff --git a/compiler2/ttcn3/compiler.l b/compiler2/ttcn3/compiler.l
index f66d30924bbb6258a5cd8ad928b701d2f5a83cbf..1f2a5a75a8ef87842382dbbd4716bea523d3d94e 100644
--- a/compiler2/ttcn3/compiler.l
+++ b/compiler2/ttcn3/compiler.l
@@ -640,6 +640,7 @@ object {
 "@abstract"      RETURN(AbstractKeyword);
 "@default"       RETURN(DefaultModifier);
 "@dynamic"       RETURN(DynamicModifier);
+"@trait"         RETURN(TraitKeyword);
 
   /* special TITAN specific keywords */
 
diff --git a/compiler2/ttcn3/compiler.y b/compiler2/ttcn3/compiler.y
index 833f066b54ae80a7100124b086bb042e96abc12e..4719104158dd8befd6b65aef49ba677a19423d52 100644
--- a/compiler2/ttcn3/compiler.y
+++ b/compiler2/ttcn3/compiler.y
@@ -847,6 +847,7 @@ static const string anyname("anytype");
 %token AbstractKeyword
 %token DefaultModifier
 %token DynamicModifier
+%token TraitKeyword
 
 /* TITAN specific keywords */
 %token TitanSpecificTryKeyword
@@ -984,6 +985,7 @@ static const string anyname("anytype");
 %type <bool_val> optAliveKeyword optOptionalKeyword
   optErrValueRaw optAllKeyword optDeterministicModifier optRealtimeClause
   optExtKeyword optFinalModifier optAbstractModifier optDefaultModifier
+  optTraitModifier
 %type <str> FreeText optLanguageSpec PatternChunk PatternChunkList
 %type <uchar_val> Group Plane Row Cell
 %type <id> FieldReference GlobalModuleId
@@ -1105,7 +1107,8 @@ static const string anyname("anytype");
 %type <type> NestedEnumDef NestedRecordDef NestedRecordOfDef NestedSetDef
   NestedSetOfDef NestedTypeDef NestedUnionDef PortDefAttribs ReferencedType
   Type TypeOrNestedTypeDef NestedFunctionTypeDef NestedAltstepTypeDef
-  NestedTestcaseTypeDef optExtendsClassDef
+  NestedTestcaseTypeDef
+%type <types> optExtendsClassDef BaseClassList
 %type <types_with_mapping> TypeList AllOrTypeList AllOrTypeListWithFrom
 AllOrTypeListWithTo TypeListWithFrom TypeListWithTo
 %type <value> AddressValue AliveOp AllPortsSpec AltGuardChar ArrayBounds
@@ -3680,16 +3683,16 @@ PortElement: // 86
 ;
 
 ClassDef:
-  optExtKeyword ClassKeyword optFinalModifier optAbstractModifier IDentifier
-  optExtendsClassDef optRunsOnSpec optMtcSpec optSystemSpec '{'
+  optExtKeyword ClassKeyword optFinalModifier optAbstractModifier optTraitModifier
+  IDentifier optExtendsClassDef optRunsOnSpec optMtcSpec optSystemSpec '{'
   optClassMemberList '}' optFinallyDef
   {
-    ClassTypeBody* class_ = new ClassTypeBody($5, $1, $3, $4, $6, $7, $8, $9,
-      $11, $13);
+    ClassTypeBody* class_ = new ClassTypeBody($6, $1, $3, $4, $5, $7, $8, $9, $10,
+      $12, $14);
     class_->set_location(infile, @$);
     Type* type = new Type(Type::T_CLASS, class_);
     type->set_location(infile, @$);
-    $$ = new Def_Type($5, type);
+    $$ = new Def_Type($6, type);
     $$->set_location(infile, @$);
     class_->set_my_def($$);
   }
@@ -3710,10 +3713,41 @@ optAbstractModifier:
 | AbstractKeyword { $$ = true; }
 ;
 
+optTraitModifier:
+  /* empty */  { $$ = false; }
+| TraitKeyword { $$ = true; }
+;
+
 optExtendsClassDef:
-  /* empty */                   { $$ = NULL; }
-| ExtendsKeyword ReferencedType { $$ = $2; }
-| ExtendsKeyword ObjectKeyword  { $$ = NULL; }
+  /* empty */                  { $$ = NULL; }
+| ExtendsKeyword BaseClassList { $$ = $2; }
+;
+
+BaseClassList:
+  ReferencedType
+  {
+    $$ = new Types;
+    $$->add_type($1);
+  }
+| ObjectKeyword
+  {
+    $$ = new Types;
+    Type* type = new Type(Type::T_CLASS);
+    type->set_location(infile, @$);
+    $$->add_type(type);
+  }
+| BaseClassList ',' ReferencedType
+  {
+    $$ = $1;
+    $$->add_type($3);
+  }
+| BaseClassList ',' ObjectKeyword
+  {
+    $$ = $1;
+    Type* type = new Type(Type::T_CLASS);
+    type->set_location(infile, @3);
+    $$->add_type(type);
+  }
 ;
 
 optFinallyDef:
diff --git a/core/OOP.hh b/core/OOP.hh
index 607d4098fab01273f859f954b99f3bc3bebca776..60795da9a042be42934c8009c04b2152bf6a8001 100644
--- a/core/OOP.hh
+++ b/core/OOP.hh
@@ -20,18 +20,17 @@
 // OBJECT
 // ------
 
-class OBJECT {
-private:
+class CLASS_BASE {
   size_t ref_count;
   boolean destructor; // true, if the destructor is currently running;
   // also makes sure the object is not deleted again when inside the destructor
-  
-  OBJECT(const OBJECT&); // copy disabled
-  OBJECT operator=(const OBJECT&); // assignment disabled
-  boolean operator==(const OBJECT&); // equality operator disabled
+
+  CLASS_BASE(const CLASS_BASE&); // copy disabled
+  CLASS_BASE operator=(const CLASS_BASE&); // assignment disabled
+  boolean operator==(const CLASS_BASE&); // equality operator disabled
 public:
-  OBJECT(): ref_count(0), destructor(FALSE) {}
-  virtual ~OBJECT() {
+  CLASS_BASE(): ref_count(0), destructor(FALSE) {}
+  virtual ~CLASS_BASE() {
     if (ref_count != 0) {
       TTCN_error("Internal error: deleting an object with %lu reference(s) left.", ref_count);
     }
@@ -45,6 +44,16 @@ public:
     destructor = ref_count == 0;
     return destructor;
   }
+};
+
+class OBJECT : public CLASS_BASE {
+private:
+  OBJECT(const OBJECT&); // copy disabled
+  OBJECT operator=(const OBJECT&); // assignment disabled
+  boolean operator==(const OBJECT&); // equality operator disabled
+public:
+  OBJECT(): CLASS_BASE() { }
+  virtual ~OBJECT() { }
   virtual void log() const {
     TTCN_Logger::log_event_str("object: { }");
   }
diff --git a/function_test/Semantic_Analyser/oop/oop_SE.ttcn b/function_test/Semantic_Analyser/oop/oop_SE.ttcn
index 21c0007bcd809b5b276b1e91911cac129f8838bf..00ea89bff2ac11534860bf878b821aa4e33d706c 100644
--- a/function_test/Semantic_Analyser/oop/oop_SE.ttcn
+++ b/function_test/Semantic_Analyser/oop/oop_SE.ttcn
@@ -49,11 +49,11 @@ template integer t := 4;
 
 type class C0 { }
 
-type class C1 extends Nonexistent { } //^In type definition// //^In superclass definition// //There is no local or imported definition with name `Nonexistent'//
+type class C1 extends Nonexistent { } //^In type definition// //^In superclass or supertrait definition// //There is no local or imported definition with name `Nonexistent'//
 
-type class C2 extends c { } //^In type definition// //^In superclass definition// //`c' is not a reference to a type//
+type class C2 extends c { } //^In type definition// //^In superclass or supertrait definition// //`c' is not a reference to a type//
 
-type class C3 extends Rec { } //^In type definition// //^In superclass definition// //Class type expected instead of `@oop_SE.Rec'//
+type class C3 extends Rec { } //^In type definition// //^In superclass or supertrait definition// //Class type expected instead of `@oop_SE.Rec'//
 
 
 type class C4 { //^In type definition//
@@ -130,11 +130,11 @@ type class C6 { //^In type definition//
 }
 
 
-type class C7 extends C9 { } //^In type definition// //^In superclass definition//
+type class C7 extends C9 { } //^In type definition// //^In superclass or supertrait definition//
 
-type class C8 extends C7 { } //^In type definition// //While checking embedded recursions\: Circular reference\: `@oop_SE.C8' -> `@oop_SE.C8.<superclass>' -> `@oop_SE.C7' -> `@oop_SE.C7.<superclass>' -> `@oop_SE.C9' -> `@oop_SE.C9.<superclass>' -> `@oop_SE.C8'//
+type class C8 extends C7 { } //^In type definition// //While checking embedded recursions\: Circular reference\: `@oop_SE.C8' -> `@oop_SE.C8.<supertraits>.<type1\>' -> `@oop_SE.C7' -> `@oop_SE.C7.<supertraits>.<type1\>' -> `@oop_SE.C9' -> `@oop_SE.C9.<supertraits>.<type1\>' -> `@oop_SE.C8'//
 
-type class C9 extends C8 { } //^In type definition// //^In superclass definition//
+type class C9 extends C8 { } //^In type definition// //^In superclass or supertrait definition//
 
 external const C0 ec_c0; //^In external constant definition// //External constant cannot be defined for class type `@oop_SE.C0'//
 external const object ec_obj; //^In external constant definition// //External constant cannot be defined for class type `object'//
@@ -346,11 +346,11 @@ function f_create() { //^In function definition//
 }
 
 
-type class @final @abstract C21 { } //^In type definition// //Final classes cannot be abstract//
+type class @final @abstract C21 { } //^In type definition// //A classes cannot have more than one of the \@final, \@abstract and \@trait modifiers//
 
 type class @final C22 { }
 
-type class C23 extends C22 { } //^In type definition// //^In superclass definition// //The superclass cannot be final//
+type class C23 extends C22 { } //^In type definition// //^In superclass or supertrait definition// //The superclass cannot be final//
 
 type class @abstract C24 { //^In type definition//
   public function @abstract f1(in Nonexistent a); //^In abstract function definition// //^In formal parameter list// //^In parameter// //There is no local or imported definition with name `Nonexistent'//
@@ -476,7 +476,7 @@ type external class @abstract C42 { //^In type definition// //External classes c
   function @abstract f(); //An external class cannot contain a function//
 }
 
-type external class C43 extends C39 { } //^In type definition// //^In superclass definition// //An external class cannot extend an internal class//
+type external class C43 extends C39 { } //^In type definition// //^In superclass or supertrait definition// //An external class cannot extend an internal class//
 
 type class C44 extends C40 { //^In type definition//
   external function f();
@@ -663,6 +663,92 @@ finally { //^In class destructor//
 }
 
 
+type class @trait T1 { //^In type definition//
+  function @abstract f();
+  create() {} //Trait class type `@oop_SE.T1' cannot have a constructor//
+  function f2() { } //^In function definition// //Trait class type `@oop_SE.T1' cannot have non-abstract methods//
+}
+
+type class @trait T2 { //^In type definition//
+  function @abstract f(); 
+  external function f3(); //^In external function definition// //Trait class type `@oop_SE.T2' cannot have non-abstract method//
+}
+finally { //^In class destructor// //Trait class type `@oop_SE.T2' cannot have a destructor//
+}
+
+type class C52 extends T1, T2 { } //^In type definition// //Missing implementation of abstract method `@oop_SE.T1.f'// //Missing implementation of abstract method `@oop_SE.T2.f'//
+
+type class C53 extends T1, T2 {
+  function f() { }
+}
+
+type class @trait T3 extends T1 {
+  function @abstract f2();
+}
+
+type class C54 extends C53, T3 {
+  function f2() { }
+}
+
+type class C55 extends T1, //^In type definition//
+  T2, //Class type `@oop_SE.T2' is already given here//
+  C54,
+  T2 { } //^In superclass or supertrait definition// //Duplicate class type in list of classes being extended//
+
+type class @trait T4 {
+  public function @abstract f1() return integer;
+}
+
+type class @trait T5 extends T4 { }
+
+type class @trait T6 {
+  public function @abstract f1(inout integer p);
+  public function @abstract f2(inout integer p);
+}
+
+type class C56 {
+  private function f1() { }
+  public function f2(inout integer p) { p := p + 1; }
+}
+
+type class C57 extends C56, T6, T5 { //^In type definition// //The prototypes of methods `f2' inherited from classes `C56' and `T6' are not identical// //The prototypes of methods `f1' inherited from classes `T4' and `T6' are not identical//
+  public function f1() return integer { return 2; } //The prototype of method `f1' is not identical to that of inherited method `@oop_SE.T6.f1'//
+}
+
+type class @trait T7 runs on CT_RunsOn {
+  public function @abstract f(in integer p) return integer;
+}
+type class @trait T8 mtc CT_Mtc { }
+type class @trait T9 system CT_System { }
+
+type class C58 extends T7, T8, T9 //^In type definition//
+  runs on Comp //The `runs on' component type of the subclass \(`@oop_SE.Comp'\) is not compatible with the `runs on' component type of supertrait `T7' \(`@oop_SE.CT_RunsOn'\)//
+  mtc Comp //The `mtc' component type of the subclass \(`@oop_SE.Comp'\) is not compatible with the `mtc' component type of supertrait `T8' \(`@oop_SE.CT_Mtc'\)//
+  system Comp //The `system' component type of the subclass \(`@oop_SE.Comp'\) is not compatible with the `system' component type of supertrait `T9' \(`@oop_SE.CT_System'\)//
+{
+  public function f(in integer p) return integer { return p + 1; }
+}
+
+type class C59 extends T7, T8, T9
+  runs on CT_RunsOn2
+  mtc CT_Mtc2
+  system CT_System2
+{
+  public function f(in integer p) return integer { return p + 1; }
+}
+
+function f_traits_bad() { //^In function definition//
+  var T7 v_t7 := C59.create; //^In variable definition// //A definition without `runs on' clause cannot create a value of class type `@oop_SE.C59', which runs on component type `@oop_SE.CT_RunsOn2'//
+  var T4 v_t4 := C54.create; //^In variable definition// //Incompatible class types: operation `create' should refer to `@oop_SE.T4' instead of `@oop_SE.C54'//
+  var object v_obj := v_t7; //^In variable definition// //Type mismatch\: a value of type `object' was expected instead of `@oop_SE.T7'//
+}
+
+function f_traits_good() runs on CT_RunsOn2 {
+  var T7 v_t7 := C59.create;
+  log(v_t7.f(3));
+}
+
+
 control { //^In control part//
   var C11 x := C11.create; //^In variable definition// //A definition without `runs on' clause cannot create a value of class type `@oop_SE.C11', which runs on component type `@oop_SE.CT_RunsOn'// //Cannot create value of class type `@oop_SE.C11', which has an `mtc' clause, in the control part.// //Cannot create value of class type `@oop_SE.C11', which has a `system' clause, in the control part.//
   raise "abc"; //^In raise statement// //Raise statement cannot be used in the control part. It is allowed only in functions, altsteps and testcases.//
diff --git a/regression_test/oop/oop.ttcn b/regression_test/oop/oop.ttcn
index f545093133c63dcd35b6e8fd1d7d31d090d7513f..75f21adb6c86e66fa76e63713b861b7280aa9bbf 100644
--- a/regression_test/oop/oop.ttcn
+++ b/regression_test/oop/oop.ttcn
@@ -202,7 +202,11 @@ type class @abstract AbstractClass {
   }
 }
 
-type class ConcreteClass extends AbstractClass {
+type class @trait TraitClass {
+  public function @abstract f_trait(in integer x) return integer;
+}
+
+type class ConcreteClass extends AbstractClass, TraitClass {
   create(octetstring p_const := 'AB'O) {
     // for compilation only, to make sure there are no name clashes between parameter default values
     log(p_const);
@@ -211,6 +215,9 @@ type class ConcreteClass extends AbstractClass {
     x := x + 1;
     return x > 0;
   }
+  public function f_trait(in integer x) return integer {
+    return x + 1;
+  }
 }
 
 
@@ -237,14 +244,17 @@ testcase tc_logging() runs on CT {
   var template float tf := (0.0 .. 10.0);
   var BaseClass v_sub := SubClass.create(4, il, "a", 'FF'O, tf);
   var BaseClass v_final := FinalClass.create(4, il, "a", 'FF'O, tf, 8, "x", -1.5, *);
+  var TraitClass v_conc := ConcreteClass.create;
 
   log(v_base);
   log(v_sub);
   log(v_final);
+  log(v_conc);
   
   var charstring v_base_str := "BaseClass";
   var charstring v_sub_str := "SubClass ( BaseClass )";
   var charstring v_final_str := "FinalClass ( SubClass ( BaseClass ) )";
+  var charstring v_conc_str := "ConcreteClass ( AbstractClass, TraitClass )";
   
   if (log2str(v_base) != v_base_str) {
     setverdict(fail, "v_base: ", v_base);
@@ -255,6 +265,9 @@ testcase tc_logging() runs on CT {
   if (log2str(v_final) != v_final_str) {
     setverdict(fail, "v_final: ", v_final);
   }
+  if (log2str(v_conc) != v_conc_str) {
+    setverdict(fail, "v_conc: ", v_conc);
+  }
   setverdict(pass);
 }
 
@@ -538,6 +551,16 @@ testcase tc_abstract() runs on CT {
   }
 }
 
+testcase tc_trait() runs on CT {
+  var TraitClass v := ConcreteClass.create;
+  if (v.f_trait(2) == 3) {
+    setverdict(pass);
+  }
+  else {
+    setverdict(fail);
+  }
+}
+
 type class Destructor { }
 finally {
   setverdict(pass);
@@ -722,6 +745,7 @@ control {
   execute(tc_function_pars_in());
   execute(tc_object());
   execute(tc_abstract());
+  execute(tc_trait());
   execute(tc_destructor());
   execute(tc_of_operator());
   execute(tc_select_class());
diff --git a/usrguide/referenceguide/4-ttcn3_language_extensions.adoc b/usrguide/referenceguide/4-ttcn3_language_extensions.adoc
index 13a42acf4d56ba63527cf3039061f0e07e141888..b099ab99e8bc514009028366b1897a0da410c595 100644
--- a/usrguide/referenceguide/4-ttcn3_language_extensions.adoc
+++ b/usrguide/referenceguide/4-ttcn3_language_extensions.adoc
@@ -9208,24 +9208,27 @@ type class MyClass {
 ----
 
 * The constructor of a subclass must call the superclass' constructor, if the super-constructor has at least one formal parameter without a default value. (This is in accordance with V1.2.1 of the standard extension, not V1.1.1.)
-* The result of logging an instance of a class contains the class name and the logging result of the superclass in round brackets, if there is a superclass.
+* The result of logging an instance of a class contains the class name and the logging result of the superclass (if there is one) and supertraits (if there are any) in round brackets, separated by commas.
 
 Logging example:
 [source]
 ----
 type class MyClass2 {
-  private var integer num;
-  private var charstring str;
+  ...
+}
+
+type class @trait MyTraitClass {
+  ...
 }
 
-type class MyClass3 extends MyClass2 {
-  private var template octetstring temp;
+type class MyClass3 extends MyClass2, MyTraitClass {
+  ...
 }
 
 ...
 
-var MyClass3 my_object := MyClass3.create(3, "abc", ?);
-log(my_object); // result: MyClass3 ( MyClass2 )
+var MyClass3 my_object := MyClass3.create(...);
+log(my_object); // result: MyClass3 ( MyClass2, MyTraitClass )
 ----
 
 NOTE: Even though every class automatically extends the built-in class `object`, if it has no superclass specified, this class does not appear in the log.
@@ -9235,9 +9238,9 @@ NOTE: Even though every class automatically extends the built-in class `object`,
 Equality example:
 [source]
 ----
-var MyClass3 my_object1 := MyClass3.create(3, "abc", ?);
+var MyClass3 my_object1 := MyClass3.create(...);
 var MyClass3 my_object2 := my_object1;
-var MyClass3 my_object3 := MyClass3.create(3, "abc", ?);
+var MyClass3 my_object3 := MyClass3.create(...);
 log(my_object1 == my_object2); // true
 log(my_object1 == my_object3); // false
 ----
@@ -9297,6 +9300,8 @@ catch(RoI[-] x) {} // catches only the element type of RoI and no other types
 module <name> "TTCN-3:2018 Object-Oriented" { ... }
 ----
 
+* Trait classes do not extend the built-in class `object`, only normal classes do.
+
 == Default alternatives of union types
 
 TITAN supports the default alternatives of union types (i.e. the `@default` modifier) described in the TTCN-3 core language standard with the clarifications and limitations described in this section.