diff --git a/compiler2/AST.cc b/compiler2/AST.cc
index 77b889de39ca18d17cadbddd0abbf254a3a56234..3f57d065e5d7c6a3e70f24ae8691186a8eef1288 100644
--- a/compiler2/AST.cc
+++ b/compiler2/AST.cc
@@ -305,6 +305,13 @@ namespace Common {
   
   void Modules::delay_type_encode_check(Type* p_type, bool p_encode)
   {
+    for (size_t i = 0; i < delayed_type_enc_v.size(); ++i) {
+      if (delayed_type_enc_v[i]->t == p_type &&
+          delayed_type_enc_v[i]->enc == p_encode) {
+        // it's already in the list of delayed checks
+        return;
+      }
+    }
     type_enc_t* elem = new type_enc_t;
     elem->t = p_type;
     elem->enc = p_encode;
diff --git a/compiler2/Type.cc b/compiler2/Type.cc
index 491eed4ce7146d8f9b06271bc4e1e6950a1a085b..58e901530dd551122c9733484dd0108a075992ed 100644
--- a/compiler2/Type.cc
+++ b/compiler2/Type.cc
@@ -607,10 +607,8 @@ namespace Common {
     chk_finished = false;
     pard_type_instance = false;
     needs_any_from_done = false;
-    encoding_by_function = false;
-    decoding_by_function = false;
-    asn_encoding = CT_UNDEF;
-    asn_decoding = CT_UNDEF;
+    default_encoding.type = CODING_UNSET;
+    default_decoding.type = CODING_UNSET;
   }
 
   void Type::clean_up()
@@ -4396,60 +4394,70 @@ namespace Common {
     }
   }
   
-  void Type::set_coding_function(bool encode, const string& function_name)
-  {
-    string& coding_function = encode ? encoding_function : decoding_function;
-    MessageEncodingType_t& asn_coding = encode ? asn_encoding : asn_decoding;
-    bool& coding_by_function = encode ?
-      encoding_by_function : decoding_by_function;
-    if (!coding_function.empty()) {
-      // leave coding_by_function as true, this will indicate that there are
-      // multiple coding functions set
-      coding_function.clear();
+  void Type::set_coding_function(bool encode, Assignment* function_def)
+  {
+    if (function_def == NULL) {
+      FATAL_ERROR("Type::set_coding_function");
     }
-    else if (asn_coding != CT_UNDEF) {
-      // a different encoding type is already set for the ASN.1 type
-      asn_coding = CT_MULTIPLE;
-      coding_function.clear();
-      return;
+    coding_t& coding = encode ? default_encoding : default_decoding;
+    if (coding.type == CODING_UNSET) {
+      // no coding method has been set yet -> OK
+      coding.type = CODING_BY_FUNCTION;
+      coding.function_def = function_def;
     }
     else {
-      if (is_asn1()) {
-        asn_coding = CT_PER;
-      }
-      coding_function = function_name;
-      coding_by_function = true;
+      // something has already been set -> not OK
+      // (the type might never be encoded/decoded, so don't report an error yet)
+      coding.type = CODING_MULTIPLE;
     }
   }
   
   void Type::set_asn_coding(bool encode, Type::MessageEncodingType_t new_coding)
   {
-    MessageEncodingType_t& coding = encode ? asn_encoding : asn_decoding;
-    bool& coding_by_function = encode ?
-      encoding_by_function : decoding_by_function; // true = PER coder is set
-    string& coding_function = encode ? encoding_function : decoding_function; // PER coder
-    if (coding == CT_UNDEF && !coding_by_function) {
-      // this is the first encoding/decoding function for this type, store it
-      // (also, no PER coders have been set for the type yet)
-      coding = new_coding;
+    coding_t& coding = encode ? default_encoding : default_decoding;
+    if (coding.type == CODING_UNSET) {
+      // no coding method has been set yet -> OK
+      coding.type = CODING_BUILT_IN;
+      coding.built_in_coding = new_coding;
     }
-    else if (coding != new_coding || coding_by_function) {
-      // there are several encoding/decoding functions declared for this type
-      // with different codings (encvalue/decvalue cannot be used in this case)
-      coding_function.clear();
-      coding = CT_MULTIPLE;
+    else if (coding.type != CODING_BUILT_IN ||
+             coding.built_in_coding != new_coding) {
+      // a different codec or a coder function has already been set -> not OK
+      // (the type might never be encoded/decoded, so don't report an error yet)
+      coding.type = CODING_MULTIPLE;
     }
   }
 
   void Type::chk_coding(bool encode, bool delayed /* = false */) {
-    string& coding_str = encode ? encoding_str : decoding_str;
-    if (!coding_str.empty())
+    coding_t& coding = encode ? default_encoding : default_decoding;
+    switch (coding.type) {
+    case CODING_BY_FUNCTION:
+    case CODING_BUILT_IN:
+      if (!delayed) {
+        // a coding method has been set by an external function's checker,
+        // but there might still be unchecked external functions out there;
+        // delay this function until everything else has been checked
+        Modules::delay_type_encode_check(this, encode);
+      }
       return;
-    bool& coding_by_function = encode ?
-      encoding_by_function : decoding_by_function;
-    Type::MessageEncodingType_t coding = CT_UNDEF;
+    case CODING_UNSET:
+      if (!delayed) {
+        // this is the only case in the switch that doesn't return immediately
+        break;
+      }
+      // else fall through
+    case CODING_MULTIPLE:
+      error("Cannot determine the %s rules for type `%s'. "
+        "%s %s external functions found%s", encode ? "encoding" : "decoding",
+        get_typename().c_str(), coding.type == CODING_UNSET ? "No" : "Multiple",
+        encode ? "encoding" : "decoding",
+        (coding.type == CODING_MULTIPLE && is_asn1()) ? " with different rules" : "");
+      return;
+    default:
+      FATAL_ERROR("Type::chk_coding");
+    }
 
-    if (!is_asn1()) {
+    if (!is_asn1()) { // TTCN-3 types
       if (!w_attrib_path) {
         error("No coding rule specified for type '%s'", get_typename().c_str());
         return;
@@ -4484,17 +4492,19 @@ namespace Common {
                 {
                   if (target->get_mapping_type() ==
                     Ttcn::TypeMappingTarget::TM_FUNCTION) {
-                    if (!coding_str.empty())
+                    if (coding.type != CODING_UNSET) {
                       target->error("Multiple definition of this target");
-                    coding_str = target->get_function()->
-                      get_genname_from_scope(my_scope);
-                    coding_by_function = true;
+                    }
+                    else {
+                      coding.type = CODING_BY_FUNCTION;
+                      coding.function_def = target->get_function();
+                    }
                   } else {
                     target->error("Only function is supported to do this mapping");
                   }
                 }
               }
-              if (coding_str.empty()) {
+              if (coding.type == CODING_UNSET) {
                 ea.warning("Extension attribute is found for %s but without "
                 "typemappings", encode ? "encvalue" : "decvalue");
               }
@@ -4516,7 +4526,7 @@ namespace Common {
         delete extatrs;
       }
 
-      if (!coding_str.empty())
+      if (coding.type != CODING_UNSET)
         return;
   end_ext:
 
@@ -4527,107 +4537,83 @@ namespace Common {
         if (real_attribs[i-1]->get_attribKeyword()
                                                 == SingleWithAttrib::AT_ENCODE) {
           found = true;
-          coding = get_enc_type(*real_attribs[i-1]);
+          coding.type = CODING_BUILT_IN;
+          coding.built_in_coding = get_enc_type(*real_attribs[i-1]);
         }
       }
-      if (coding == CT_UNDEF) {
+      if (coding.type == CODING_UNSET) {
         // no "encode" attribute found
         error("No coding rule specified for type '%s'", get_typename().c_str());
         return;
       }
-    }
-    else { // ASN.1 type
-      coding = encode ? asn_encoding : asn_decoding;
-      if ((coding == CT_UNDEF && delayed) || coding == CT_MULTIPLE) {
-        // either this is the delayed call and no external functions have been
-        // found, or there was already more than one function
-        error("Cannot determine the %s rules for ASN.1 type `%s'. "
-          "%s %s external functions found%s", encode ? "encoding" : "decoding",
-          get_typename().c_str(), coding == CT_UNDEF ? "No" : "Multiple",
-          encode ? "encoding" : "decoding",
-          coding == CT_UNDEF ? "" : " with different rules");
-        return;
-      }
-      if (!delayed) {
-        // there have been no errors so far in determining the coding type,
-        // but there might still be unchecked external functions out there;
+      if (coding.built_in_coding == CT_CUSTOM) {
+        // the type has a custom encoding attribute, but no external coder
+        // function with that encoding has been found yet;
         // delay this function until everything else has been checked
         Modules::delay_type_encode_check(this, encode);
-        return;
+        // set the coding type back to UNSET for delayed call
+        coding.type = CODING_UNSET;
+      }
+      else if (!has_encoding(coding.built_in_coding)) {
+        error("Type '%s' cannot be coded with the selected method '%s'",
+          get_typename().c_str(), get_encoding_name(coding.built_in_coding));
       }
     }
-    if (coding != CT_CUSTOM && !has_encoding(coding)) {
-      error("Type '%s' cannot be coded with the selected method '%s'",
-            get_typename().c_str(),
-            get_encoding_name(coding));
-      return;
-    }
-    switch (coding) {
-      case CT_RAW:
-        coding_str = "RAW";
-        break;
-      case CT_TEXT:
-        coding_str = "TEXT";
-        break;
-      case CT_XER:
-        coding_str = "XER, XER_EXTENDED"; // TODO: fine tuning this parameter
-        break;
-      case CT_JSON:
-        coding_str = "JSON, FALSE"; // with compact printing
-        break;
-      case CT_BER: {
-        coding_str = "BER, ";
-        BerAST* ber = berattrib;
-        if (!ber)  // use default settings if attributes are not specified
-          ber = new BerAST;
-        if (encode)
-          coding_str += ber->get_encode_str();
-        else
-          coding_str += ber->get_decode_str();
-        if (!berattrib)
-          delete ber;
-        break; }
-      case CT_PER:
-      case CT_CUSTOM: {
-        // the coding function is set by its semantic checker in this case
-        string& coding_function = encode ? encoding_function : decoding_function;
-        if (coding_function.empty() && coding_by_function) {
-          error("Multiple %s %s functions set for type `%s'",
-            get_encoding_name(coding), encode ? "encoding" : "decoding",
-            get_typename().c_str());
-        }
-        else if (!delayed) {
-          // there have been no errors so far in determining the coding function,
-          // but there might still be unchecked external functions out there;
-          // delay this function until everything else has been checked
-          Modules::delay_type_encode_check(this, encode);
-        }        
-        else if (coding_function.empty()) {
-          // this is the delayed call, and the coding function has still not been set
-          error("No %s %s function found for type `%s'", get_encoding_name(coding),
-            encode ? "encoding" : "decoding", get_typename().c_str());
-        }
-        else {
-          // this is the delayed call, and exactly one coding function has been set
-          coding_str = coding_function;
-        }
-        return; }
-      default:
-        error("Unknown coding selected for type '%s'", get_typename().c_str());
-        break;
+    else { // ASN.1 type
+      // delay this function until everything else has been checked, in case
+      // there is an encoder/decoder external function out there for this type
+      Modules::delay_type_encode_check(this, encode);
     }
-    coding_by_function = false;
   }
 
   bool Type::is_coding_by_function(bool encode) const {
-    return encode ? encoding_by_function : decoding_by_function;
+    return (encode ? default_encoding : default_decoding).type == CODING_BY_FUNCTION;
   }
-
-  const string& Type::get_coding(bool encode) const {
-    if (encode)
-      return encoding_str;
-    else
-      return decoding_str;
+  
+  string Type::get_coding(bool encode) const
+  {
+    const coding_t& coding = encode ? default_encoding : default_decoding;
+    if (coding.type != CODING_BUILT_IN) {
+      FATAL_ERROR("Type::get_built_in_coding");
+    }
+    switch (coding.built_in_coding) {
+    case CT_RAW:
+      return string("RAW");
+    case CT_TEXT:
+      return string("TEXT");
+    case CT_XER:
+      return string("XER, XER_EXTENDED"); // TODO: fine tuning this parameter
+    case CT_JSON:
+      if (encode) {
+        return string("JSON, FALSE"); // with compact printing
+      }
+      else {
+        return string("JSON");
+      }
+    case CT_BER: {
+      string coding_str = string("BER, ");
+      BerAST* ber = berattrib;
+      if (!ber)  // use default settings if attributes are not specified
+        ber = new BerAST;
+      if (encode)
+        coding_str += ber->get_encode_str();
+      else
+        coding_str += ber->get_decode_str();
+      if (!berattrib)
+        delete ber;
+      return coding_str; }
+    default:
+      FATAL_ERROR("Type::get_built_in_coding");
+    }
+  }
+  
+  Assignment* Type::get_coding_function(bool encode) const
+  {
+    const coding_t& coding = encode ? default_encoding : default_decoding;
+    if (coding.type != CODING_BY_FUNCTION) {
+      FATAL_ERROR("Type::get_coding_function");
+    }
+    return coding.function_def;
   }
 
   namespace { // unnamed
diff --git a/compiler2/Type.hh b/compiler2/Type.hh
index c1e442cc4ef96eeeaa3b239ef39dab592df1cbdf..b24291fb35159d6638d432780c246c98a54e5c6e 100644
--- a/compiler2/Type.hh
+++ b/compiler2/Type.hh
@@ -114,6 +114,7 @@ namespace Common {
   class SignatureParamList;
   class SignatureExceptions;
   class CodeGenHelper;
+  class Assignment;
 
   /**
    * This is the base class for types.
@@ -195,14 +196,13 @@ namespace Common {
      */
     enum MessageEncodingType_t {
       CT_UNDEF, /**< undefined/unused */
-      CT_BER,   /**< ASN.1 BER */
-      CT_PER,   /**< ASN.1 PER (not supported yet) */
-      CT_RAW,   /**< TTCN-3 RAW */
-      CT_TEXT,  /**< TTCN-3 TEXT */
-      CT_XER,    /**< ASN.1 XER */
-      CT_JSON,   /**< TTCN-3 JSON */
-      CT_CUSTOM, /**< user defined encoding */
-      CT_MULTIPLE /**< multiple codings defined for an ASN.1 type */
+      CT_BER,   /**< ASN.1 BER (built-in) */
+      CT_PER,   /**< ASN.1 PER (through user defined coder functions) */
+      CT_RAW,   /**< TTCN-3 RAW (built-in) */
+      CT_TEXT,  /**< TTCN-3 TEXT (built-in) */
+      CT_XER,    /**< TTCN-3 XER (built-in) */
+      CT_JSON,   /**< TTCN-3 and ASN.1 JSON (built-in) */
+      CT_CUSTOM  /**< user defined encoding (through user defined coder functions) */
     };
 
     /** selector for value checking algorithms */
@@ -225,7 +225,7 @@ namespace Common {
     };
 
     /** Enumeration to represent the owner of the type.
-     *  Also align OT_UNKNOWN at line 200. */
+      */
     enum TypeOwner_t {
       OT_UNKNOWN,
       OT_TYPE_ASS, ///< ASN.1 type assignment (Ass_T)
@@ -261,6 +261,31 @@ namespace Common {
       OT_SIG_PAR, ///< signature parameter (SignatureParam)
       OT_POOL ///< It's a pool type, owned by the type pool
     };
+    
+    /**
+     * Enumeration to represent the default method of encoding or decoding for a type.
+     */
+    enum coding_type_t {
+      CODING_UNSET, ///< No encoding/decoding method has been set for the type.
+      CODING_BUILT_IN, ///< The type uses a built-in codec for encoding/decoding.
+      CODING_BY_FUNCTION, ///< The type uses a user defined function for encoding/decoding.
+      CODING_MULTIPLE ///< Multiple encoding/decoding methods have been set for the type.
+    };
+    
+    /**
+     * Structure containing the default encoding or decoding settings for a type.
+     * These settings determine how values of the type are encoded or decoded by
+     * the following TTCN-3 language elements:
+     * 'encvalue' (encode), 'encvalue_unichar' (encode), 'decvalue' (decode),
+     * 'decvalue_unichar' (decode), 'decmatch' (decode) and '@decoded' (decode).
+     */
+    struct coding_t {
+      coding_type_t type; ///< Type of encoding/decoding
+      union {
+        MessageEncodingType_t built_in_coding; ///< Built-in codec (if type is CODING_BUILT_IN)
+        Assignment* function_def; ///< Pointer to external function definition (if type is CODING_BY_FUNCTION)
+      };
+    };
 
     /** Returns the display string of \a encoding_type. */
     static const char *get_encoding_name(MessageEncodingType_t encoding_type);
@@ -305,14 +330,9 @@ namespace Common {
     vector<SubTypeParse> *parsed_restr; ///< parsed subtype restrictions are stored here until they are moved to the sub_type member
     SubType *sub_type; ///< effective/aggregate subtype of this type, NULL if neither inherited nor own subtype restrictions exist
 
-    string encoding_str;  // needed by codegen for encvalue() and decvalue()
-    string decoding_str;
-    bool encoding_by_function;  // false - coding attribute is set, true - coding via coding function
-    bool decoding_by_function;  // same for decoding
-    string encoding_function; // name of custom or PER encoder
-    string decoding_function; // name of custom or PER decoder
-    MessageEncodingType_t asn_encoding; // set by the semantic analysis of encoding
-    MessageEncodingType_t asn_decoding; // and decoding external functions for ASN.1 types
+    coding_t default_encoding; ///< default settings for encoding values of this type
+    coding_t default_decoding; ///< default settings for decoding values of this type
+    
     /** What kind of AST element owns the type.
      *  It may not be known at creation type, so it's initially OT_UNKNOWN.
      *  We want this information so we don't have to bother with XER
@@ -658,12 +678,35 @@ namespace Common {
     bool is_list_type(bool allow_array);
 
     /** Sets the encoding or decoding function for the type (in case of custom
-      * encoding). */
-    void set_coding_function(bool encode, const string& function_name);
+      * or PER encoding). */
+    void set_coding_function(bool encode, Assignment* function_def);
+    
+    /** Sets the codec to use when encoding or decoding the ASN.1 type */
     void set_asn_coding(bool encode, MessageEncodingType_t new_coding);
+    
+    /** Determines the method of encoding or decoding for values of this type
+      * based on its attributes and on encoder or decoder function definitions
+      * with this type as their input or output. An error is displayed if the
+      * coding method cannot be determined.
+      *
+      * @note Because this check depends on the checks of other AST elements
+      * (external functions), it is sometimes delayed to the end of the semantic
+      * analysis. */
     void chk_coding(bool encode, bool delayed = false);
+    
+    /** Indicates whether the type is encoded/decoded by a function or by a
+      * built-in codec. */
     bool is_coding_by_function(bool encode) const;
-    const string& get_coding(bool encode) const;
+    
+    /** Returns the string representation of the type's default codec.
+      * Used during code generation for types encoded/decoded by a built-in
+      * codec. */
+    string get_coding(bool encode) const;
+    
+    /** Returns the function definition of the type's encoder/decoder function.
+      * Used during code generation for types encoded/decoded by functions. */
+    Assignment* get_coding_function(bool encode) const;
+    
   private:
     static MessageEncodingType_t get_enc_type(const Ttcn::SingleWithAttrib& enc);
 
diff --git a/compiler2/Value.cc b/compiler2/Value.cc
index cf273f8a624020f5947d76cbde328a935dc11495..470a6870f73b8189194caa5b7337453160f033de 100644
--- a/compiler2/Value.cc
+++ b/compiler2/Value.cc
@@ -12970,6 +12970,7 @@ error:
       break;
     }
 
+    Scope* scope = u.expr.ti1->get_Template()->get_my_scope();
     if (!gov_last->is_coding_by_function(true)) {
       const string& tmp_id = get_temporary_id();
       const string& tmp_buf_id = get_temporary_id();
@@ -12983,9 +12984,7 @@ error:
         expr->preamble = mputc  (expr->preamble, '\n');
       }
       expr->preamble = mputprintf(expr->preamble, "%s const& %s = %s",
-        gov_last->get_genname_typedescriptor(
-          u.expr.ti1->get_Template()->get_my_scope()
-        ).c_str(),
+        gov_last->get_genname_typedescriptor(scope).c_str(),
         tmp_ref_id.c_str(),
         expr2.expr);
       if (is_templ) // make a value out of the template, if needed
@@ -12993,9 +12992,7 @@ error:
       expr->preamble = mputprintf(expr->preamble,
         ";\n%s.encode(%s_descr_, %s, TTCN_EncDec::CT_%s",
         tmp_ref_id.c_str(),
-        gov_last->get_genname_typedescriptor(
-          u.expr.ti1->get_Template()->get_my_scope()
-        ).c_str(),
+        gov_last->get_genname_typedescriptor(scope).c_str(),
         tmp_buf_id.c_str(),
         gov_last->get_coding(true).c_str()
       );
@@ -13009,8 +13006,8 @@ error:
         expr->postamble = mputstr(expr->postamble, expr2.postamble);
     } else
       expr->expr = mputprintf(expr->expr, "%s(%s%s)",
-        gov_last->get_coding(true).c_str(), expr2.expr,
-        is_templ ? ".valueof()" : "");
+        gov_last->get_coding_function(true)->get_genname_from_scope(scope).c_str(),
+        expr2.expr, is_templ ? ".valueof()" : "");
     Code::free_expr(&expr2);
   }
   
@@ -13031,6 +13028,7 @@ error:
     if (expr2.preamble)
       expr->preamble = mputprintf(expr->preamble, "%s", expr2.preamble);
 
+    Scope* scope = u.expr.r2->get_my_scope();
     if (!_type->is_coding_by_function(false)) {
       const string& tmp_id = get_temporary_id();
       const string& buffer_id = get_temporary_id();
@@ -13052,9 +13050,7 @@ error:
         "%s%s.decode(%s_descr_, %s, TTCN_EncDec::CT_%s);\n",
         expr2.expr,
         optional ? "()" : "",
-          _type->get_genname_typedescriptor(
-            u.expr.r2->get_my_scope()
-          ).c_str(),
+          _type->get_genname_typedescriptor(scope).c_str(),
           buffer_id.c_str(),
           _type->get_coding(false).c_str()
       );
@@ -13090,7 +13086,7 @@ error:
       expr->expr = mputprintf(expr->expr, "%s", retval_id.c_str());
     } else
       expr->expr = mputprintf(expr->expr, "%s(%s, %s)",
-        _type->get_coding(false).c_str(), expr1.expr, expr2.expr);
+        _type->get_coding_function(false)->get_genname_from_scope(scope).c_str(), expr1.expr, expr2.expr);
     if (expr1.postamble)
       expr->postamble = mputprintf(expr->postamble, "%s", expr1.postamble);
     if (expr2.postamble)
@@ -13127,6 +13123,7 @@ void Value::generate_code_expr_encvalue_unichar(expression_struct *expr)
       v2_code = generate_code_char_coding_check(expr, u.expr.v2, "encvalue_unichar");
     }
 
+    Scope* scope = u.expr.ti1->get_Template()->get_my_scope();
     if (!gov_last->is_coding_by_function(true)) {
       const string& tmp_id = get_temporary_id();
       const string& tmp_buf_id = get_temporary_id();
@@ -13140,9 +13137,7 @@ void Value::generate_code_expr_encvalue_unichar(expression_struct *expr)
         expr->preamble = mputc  (expr->preamble, '\n');
       }
       expr->preamble = mputprintf(expr->preamble, "%s const& %s = %s",
-        gov_last->get_genname_typedescriptor(
-          u.expr.ti1->get_Template()->get_my_scope()
-        ).c_str(),
+        gov_last->get_genname_typedescriptor(scope).c_str(),
         tmp_ref_id.c_str(),
         expr2.expr);
       if (is_templ) // make a value out of the template, if needed
@@ -13150,9 +13145,7 @@ void Value::generate_code_expr_encvalue_unichar(expression_struct *expr)
       expr->preamble = mputprintf(expr->preamble,
         ";\n%s.encode(%s_descr_, %s, TTCN_EncDec::CT_%s",
         tmp_ref_id.c_str(),
-        gov_last->get_genname_typedescriptor(
-          u.expr.ti1->get_Template()->get_my_scope()
-        ).c_str(),
+        gov_last->get_genname_typedescriptor(scope).c_str(),
         tmp_buf_id.c_str(),
         gov_last->get_coding(true).c_str()
       );
@@ -13172,8 +13165,8 @@ void Value::generate_code_expr_encvalue_unichar(expression_struct *expr)
         expr->postamble = mputstr(expr->postamble, expr2.postamble);
     } else {
       expr->expr = mputprintf(expr->expr, "oct2unichar(bit2oct(%s(%s%s))",
-        gov_last->get_coding(true).c_str(), expr2.expr,
-        is_templ ? ".valueof()" : "");
+        gov_last->get_coding_function(true)->get_genname_from_scope(scope).c_str(),
+        expr2.expr, is_templ ? ".valueof()" : "");
       if(u.expr.v2) {
         expr->expr = mputprintf(expr->expr, ", %s", v2_code);
       } else {
@@ -13205,6 +13198,7 @@ void Value::generate_code_expr_encvalue_unichar(expression_struct *expr)
       v3_code = generate_code_char_coding_check(expr, u.expr.v3, "decvalue_unichar");
     }
 
+    Scope* scope = u.expr.r2->get_my_scope();
     if (!_type->is_coding_by_function(false)) {
       const string& tmp_id = get_temporary_id();
       const string& buffer_id = get_temporary_id();
@@ -13227,9 +13221,7 @@ void Value::generate_code_expr_encvalue_unichar(expression_struct *expr)
         "%s%s.decode(%s_descr_, %s, TTCN_EncDec::CT_%s);\n",
         expr2.expr,
         optional ? "()" : "",
-          _type->get_genname_typedescriptor(
-            u.expr.r2->get_my_scope()
-          ).c_str(),
+          _type->get_genname_typedescriptor(scope).c_str(),
           buffer_id.c_str(),
           _type->get_coding(false).c_str()
       );
@@ -13275,7 +13267,9 @@ void Value::generate_code_expr_encvalue_unichar(expression_struct *expr)
         "%s = oct2unichar(bit2oct(%s), %s);\n",
         ustr_ref_id.c_str(), expr1.expr,
         bstr_id.c_str(), ustr_ref_id.c_str(), u.expr.v3 ? v3_code : "\"UTF-8\"",
-        ret_val_id.c_str(), _type->get_coding(false).c_str(), bstr_id.c_str(), expr2.expr,
+        ret_val_id.c_str(),
+        _type->get_coding_function(false)->get_genname_from_scope(scope).c_str(),
+        bstr_id.c_str(), expr2.expr,
         ustr_ref_id.c_str(), bstr_id.c_str(), u.expr.v3 ? v3_code : "\"UTF-8\"");
       expr->expr = mputprintf(expr->expr, "%s", ret_val_id.c_str());
     }
diff --git a/compiler2/ttcn3/AST_ttcn3.cc b/compiler2/ttcn3/AST_ttcn3.cc
index 38453629180a4e1b29b828ba92afdeaf88e3576f..aa181479c96824820c7eec28c79565cc9296a425 100644
--- a/compiler2/ttcn3/AST_ttcn3.cc
+++ b/compiler2/ttcn3/AST_ttcn3.cc
@@ -6569,8 +6569,7 @@ namespace Ttcn {
             }
             else {
               // let the input type know that this is its encoding function
-              input_type->get_type_refd()->set_coding_function(true,
-                get_genname_from_scope(input_type->get_type_refd()->get_my_scope()));
+              input_type->get_type_refd()->set_coding_function(true, this);
               // treat this as a manual external function during code generation
               function_type = EXTFUNC_MANUAL;
             }
@@ -6692,8 +6691,7 @@ namespace Ttcn {
           }
           else if (output_type) {
             // let the output type know that this is its decoding function
-            output_type->get_type_refd()->set_coding_function(false,
-              get_genname_from_scope(output_type->get_type_refd()->get_my_scope()));
+            output_type->get_type_refd()->set_coding_function(false, this);
             // treat this as a manual external function during code generation
             function_type = EXTFUNC_MANUAL;
           }
diff --git a/compiler2/ttcn3/Statement.cc b/compiler2/ttcn3/Statement.cc
index 8452c0229be9c81d4cdec46ba79079dbad0c11c0..a10b05ba7302b165f5955110fa91e15f3f1c249a 100644
--- a/compiler2/ttcn3/Statement.cc
+++ b/compiler2/ttcn3/Statement.cc
@@ -9350,8 +9350,8 @@ error:
               "TTCN_error(\"Parameter redirect (for parameter '%s') failed, "
               "because the buffer was not empty after decoding. "
               "Remaining bits: %%d.\", buff.lengthof());\n"
-              "}\n", ve->get_dec_type()->get_coding(false).c_str(),
-              par_name, par_name, par_name);
+              "}\n", ve->get_dec_type()->get_coding_function(false)->
+              get_genname_from_scope(scope).c_str(), par_name, par_name, par_name);
           }
           else { // built-in decoding
             switch (tt) {
@@ -10097,7 +10097,8 @@ error:
                 "TTCN_error(\"Value redirect #%d failed, because the buffer was "
                 "not empty after decoding. Remaining bits: %%d.\", "
                 "buff_%d.lengthof());\n"
-                "}\n", member_type->get_coding(false).c_str(),
+                "}\n", member_type->get_coding_function(false)->
+                get_genname_from_scope(scope).c_str(),
                 (int)i, (int)i, (int)(i + 1), (int)i, (int)(i + 1), (int)i);
             }
             else { // built-in decoding
diff --git a/compiler2/ttcn3/TtcnTemplate.cc b/compiler2/ttcn3/TtcnTemplate.cc
index 0dc39effb84bef0efe83045f8fde3a3419f8d44f..330316ffcc92c5dfb57d43013a227202a0f56202 100644
--- a/compiler2/ttcn3/TtcnTemplate.cc
+++ b/compiler2/ttcn3/TtcnTemplate.cc
@@ -4597,7 +4597,7 @@ compile_time:
         "}\n"
         // make sure the bitstring is empty after decoding, display a warning otherwise
         "else if (bs.lengthof() != 0) {\n",
-        target_type->get_coding(false).c_str());
+        target_type->get_coding_function(false)->get_genname_from_scope(my_scope).c_str());
     }
     else {
       str = mputprintf(str,
diff --git a/function_test/Semantic_Analyser/encode/Types_A.asn b/function_test/Semantic_Analyser/encode/Types_A.asn
index 4a7fbdcdda566b8f3b262615211c702e4ed731bd..c9913de00a9c5bcf98e7bc01cfdff14496e7e826 100644
--- a/function_test/Semantic_Analyser/encode/Types_A.asn
+++ b/function_test/Semantic_Analyser/encode/Types_A.asn
@@ -20,7 +20,7 @@ IMPORTS;
 
 Int ::= INTEGER
 
-Seq ::= SEQUENCE { --//Cannot determine the encoding rules for ASN.1 type `@Types-A.Seq'. Multiple encoding external functions found with different rules// //Cannot determine the decoding rules for ASN.1 type `@Types-A.Seq'. Multiple decoding external functions found with different rules//
+Seq ::= SEQUENCE { --//Cannot determine the encoding rules for type `@Types-A.Seq'. Multiple encoding external functions found with different rules// //Cannot determine the decoding rules for type `@Types-A.Seq'. Multiple decoding external functions found with different rules//
   num INTEGER,
   str VisibleString
 }
@@ -30,11 +30,11 @@ Set ::= SET {
   str VisibleString
 }
 
-SeqOf ::= SEQUENCE OF INTEGER --//Multiple PER encoding functions set for type// //Multiple PER decoding functions set for type//
+SeqOf ::= SEQUENCE OF INTEGER --//Cannot determine the encoding rules for type `@Types-A.SeqOf'. Multiple encoding external functions found with different rules// //Cannot determine the decoding rules for type `@Types-A.SeqOf'. Multiple decoding external functions found with different rules//
 
 SetOf ::= SET OF INTEGER
 
-Choice ::= CHOICE { --//Cannot determine the encoding rules for ASN.1 type `@Types-A.Choice'. Multiple encoding external functions found with different rules// //Cannot determine the decoding rules for ASN.1 type `@Types-A.Choice'. No decoding external functions found//
+Choice ::= CHOICE { --//Cannot determine the encoding rules for type `@Types-A.Choice'. Multiple encoding external functions found with different rules// //Cannot determine the decoding rules for type `@Types-A.Choice'. No decoding external functions found//
   num INTEGER,
   str VisibleString
 }
diff --git a/function_test/Semantic_Analyser/encode/encode_asn_SE.ttcn b/function_test/Semantic_Analyser/encode/encode_asn_SE.ttcn
index 74ad46d660c70d02027d1378e143f3694ae7c4b8..ad675829bf74878bdb76d237fe8d8575cca76afd 100644
--- a/function_test/Semantic_Analyser/encode/encode_asn_SE.ttcn
+++ b/function_test/Semantic_Analyser/encode/encode_asn_SE.ttcn
@@ -84,9 +84,9 @@ external function f_enc_seqof2(in SeqOf x) return bitstring
 external function f_dec_seqof1(inout bitstring x, out SeqOf y) return integer
   with { extension "prototype(sliding) decode(PER)" }
 
-function f3() {
+function f3() { //^In function definition//
   var SeqOf x := { 1, 2 };
-  var bitstring y := encvalue(x);
+  var bitstring y := encvalue(x); //^In variable definition// //^In the parameter of encvalue//
   var integer res := decvalue(y, x);
 }
 
diff --git a/function_test/Semantic_Analyser/encode/encode_ttcn_SE.ttcn b/function_test/Semantic_Analyser/encode/encode_ttcn_SE.ttcn
index 1de761b6d15f61ff095bcb69eaa84066fceb3a7a..e59db46b6ce82dc2b88bc28a161614a2d2768068 100644
--- a/function_test/Semantic_Analyser/encode/encode_ttcn_SE.ttcn
+++ b/function_test/Semantic_Analyser/encode/encode_ttcn_SE.ttcn
@@ -14,9 +14,9 @@ module encode_ttcn_SE { //^In TTCN-3 module//
 
 
 /* types with no coder functions */
-type integer AnInt with { encode "nonexistent" }; //^error\: No custom decoding function found for type//
+type integer AnInt with { encode "nonexistent" }; //Cannot determine the decoding rules for type `integer'. No decoding external functions found//
 
-type record ARecord { //^error\: No custom decoding function found for type//
+type record ARecord { //Cannot determine the decoding rules for type `@encode_ttcn_SE.ARecord'. No decoding external functions found//
   integer i,
   octetstring os
 }
@@ -54,7 +54,7 @@ external function f_dec_list4(inout charstring x, out AList y) return integer //
  
 
 /* type with multiple custom coding functions */ 
-type union AUnion { //Multiple custom encoding functions set for type// //Multiple custom decoding functions set for type//
+type union AUnion { //Cannot determine the encoding rules for type `@encode_ttcn_SE.AUnion'. Multiple encoding external functions found// //Cannot determine the decoding rules for type `@encode_ttcn_SE.AUnion'. Multiple decoding external functions found//
   octetstring field
 }
 with {
diff --git a/regression_test/customEncoding/Coders.cc b/regression_test/customEncoding/Coders.cc
index 9fc5647d3b42ca6aeaac7591b7cd63c1ce2f1bbe..4318f4ed87d9a6496486ed4cd8d93119bd9eeac1 100644
--- a/regression_test/customEncoding/Coders.cc
+++ b/regression_test/customEncoding/Coders.cc
@@ -58,6 +58,18 @@ INTEGER f__dec__uni(BITSTRING& b, Custom1::Uni& x)
   }
 }
 
+BITSTRING f__enc__bs(const BITSTRING& x)
+{
+  return x;
+}
+
+INTEGER f__dec__bs(BITSTRING& b, BITSTRING& x)
+{
+  x = b;
+  b = BITSTRING(0, NULL);
+  return 0;
+}
+
 } // namespace Custom2
 
 namespace Custom1 {
diff --git a/regression_test/customEncoding/Coders.hh b/regression_test/customEncoding/Coders.hh
index ba40254300d3fd9d0c9b47c77d4f3c9f1ea06480..ca2af2acf901afb62790ad063a4e338915741973 100644
--- a/regression_test/customEncoding/Coders.hh
+++ b/regression_test/customEncoding/Coders.hh
@@ -27,6 +27,9 @@ INTEGER f__dec__rec(BITSTRING& b, Custom3::Rec& x);
 BITSTRING f__enc__uni(const Custom1::Uni& x);
 INTEGER f__dec__uni(BITSTRING& b, Custom1::Uni& x);
 
+BITSTRING f__enc__bs(const BITSTRING& x);
+INTEGER f__dec__bs(BITSTRING& b, BITSTRING& x);
+
 }
 
 namespace Custom1 {
diff --git a/regression_test/customEncoding/Custom1.ttcn b/regression_test/customEncoding/Custom1.ttcn
index 168ecaef8cce7f72b53fd6a56ff0aa3b87679370..4832eadb9123a958fa788834e725a21fe3940025 100644
--- a/regression_test/customEncoding/Custom1.ttcn
+++ b/regression_test/customEncoding/Custom1.ttcn
@@ -142,6 +142,29 @@ testcase tc_custom3() runs on CT
 }
 
 // Test 4.
+// The encoded type and the coding functions are in another module (in the same other module).
+testcase tc_custom4() runs on CT
+{
+  var BitString x := '10010110'B;
+  var bitstring enc_exp := x;
+  var BitString dec_exp := x;
+  
+  var bitstring enc := encvalue(x);
+  if (enc != enc_exp) {
+    setverdict(fail, "Expected: ", enc_exp, ", got: ", enc);
+  }
+  var BitString dec;
+  var integer res := decvalue(enc_exp, dec);
+  if (res != 0) {
+    setverdict(fail, "Failed to decode ", enc_exp);
+  }
+  if (dec != dec_exp) {
+    setverdict(fail, "Expected: ", dec_exp, ", got: ", dec);
+  }
+  setverdict(pass);
+}
+
+// Test 5.
 // Using encvalue on templates and template variables
 // Same type and encoding function as test 1
 testcase tc_custom_temp() runs on CT
@@ -162,7 +185,7 @@ testcase tc_custom_temp() runs on CT
   setverdict(pass);
 }
 
-// Test 5.
+// Test 6.
 // Same as test 2, but with encvalue_unichar and decvalue_unichar.
 // The input RecOf has also been adjusted, so it doesn't cause problems for the UTF-8 decoder.
 testcase tc_custom_unichar() runs on CT
@@ -186,7 +209,7 @@ testcase tc_custom_unichar() runs on CT
   setverdict(pass);
 }
 
-// Test 6.
+// Test 7.
 // Using custom encoding on a decoded parameter redirect.
 // Same input value as in test 5.
 testcase tc_custom_param_redirect() runs on CT
@@ -217,7 +240,7 @@ testcase tc_custom_param_redirect() runs on CT
   }
 }
 
-// Test 7.
+// Test 8.
 // Using custom encoding in a template with decoded content matching.
 // Same input as test 3.
 testcase tc_custom_decmatch() runs on CT
@@ -249,7 +272,7 @@ external function f_enc_seq(in Seq x) return octetstring
 external function f_dec_seq(in octetstring x) return Seq
   with { extension "prototype(convert) decode(JSON)" };
   
-// Test 8.
+// Test 9.
 // Using encvalue and decvalue on the ASN.1 type Seq (with JSON encoding).
 testcase tc_asn() runs on CT
 {
@@ -272,7 +295,7 @@ testcase tc_asn() runs on CT
   setverdict(pass);
 }
 
-// Test 9.
+// Test 10.
 // The redirected parameter is decoded into a value of ASN.1 type Seq.
 // Same input value as in test 8.
 testcase tc_asn_param_redirect() runs on CT
@@ -303,7 +326,7 @@ testcase tc_asn_param_redirect() runs on CT
   }
 }
 
-// Test 10.
+// Test 11.
 // Decoded content matching against a value of ASN.1 type Seq.
 // Same input value as in test 8.
 testcase tc_asn_decmatch() runs on CT
@@ -336,7 +359,7 @@ external function f_enc_seqof(in SeqOf x) return bitstring
 external function f_dec_seqof(inout bitstring x, out SeqOf y) return integer
   with { extension "prototype(sliding) decode(PER)" };
   
-// Test 11.
+// Test 12.
 // PER coder with encvalue and decvalue.
 testcase tc_per() runs on CT
 {
@@ -360,7 +383,7 @@ testcase tc_per() runs on CT
   setverdict(pass);
 }
 
-// Test 12.
+// Test 13.
 // The redirected parameter is decoded using the PER coder.
 // Same input value as in test 11.
 testcase tc_per_param_redirect() runs on CT
@@ -391,7 +414,7 @@ testcase tc_per_param_redirect() runs on CT
   }
 }
 
-// Test 13.
+// Test 14.
 // Decoded content matching with the PER coder.
 // Same input value as in test 11.
 testcase tc_per_decmatch() runs on CT
@@ -424,7 +447,7 @@ external function f_enc_choice(in Choice x) return bitstring
 external function f_dec_choice(inout bitstring x, out Choice y) return integer
   with { extension "prototype(sliding) decode(PER)" };
 
-// Test 14.
+// Test 15.
 // Encoding an ASN.1 type with JSON (built-in) and decoding the same type with PER (manual).
 testcase tc_asn_mixed() runs on CT
 {
@@ -454,6 +477,7 @@ control {
   execute(tc_custom1());
   execute(tc_custom2());
   execute(tc_custom3());
+  execute(tc_custom4());
   execute(tc_custom_temp());
   execute(tc_custom_unichar());
   execute(tc_custom_param_redirect());
diff --git a/regression_test/customEncoding/Custom2.ttcn b/regression_test/customEncoding/Custom2.ttcn
index 0b30a289f41cecc60b8d883931d9959b1c40496d..b14a6b5054914906837b95884565f7cf0d91370b 100644
--- a/regression_test/customEncoding/Custom2.ttcn
+++ b/regression_test/customEncoding/Custom2.ttcn
@@ -30,4 +30,14 @@ external function f_enc_uni(in Uni x) return bitstring
 external function f_dec_uni(inout bitstring b, out Uni x) return integer
   with { extension "prototype(sliding) decode(globalCustom)" }
 
+// Type for test 4
+type bitstring BitString with { encode "nothing" };
+
+// Coding function declarations for test 4
+external function f_enc_bs(in BitString x) return bitstring
+  with { extension "prototype(convert) encode(nothing)" }
+  
+external function f_dec_bs(inout bitstring b, out BitString x) return integer
+  with { extension "prototype(sliding) decode(nothing)" }
+
 }
diff --git a/regression_test/customEncoding/Custom4.ttcn b/regression_test/customEncoding/Custom4.ttcn
index 9a6bfbe50f5a180d92d7efb22f9ec0b4d251ad8b..aa9cec62b677fa8160b8172abf16d7e209c7d9f7 100644
--- a/regression_test/customEncoding/Custom4.ttcn
+++ b/regression_test/customEncoding/Custom4.ttcn
@@ -19,7 +19,7 @@ import from Custom2 all;
 import from Custom3 all;
 import from Types all;
 
-// Test 15 (RT2 only).
+// Test 16 (RT2 only).
 // Using custom encoding on a decoded value redirect.
 // Same input value as in test 1.
 testcase tc_custom_value_redirect() runs on CT
@@ -50,7 +50,7 @@ testcase tc_custom_value_redirect() runs on CT
   }
 }
 
-// Test 16 (RT2 only).
+// Test 17 (RT2 only).
 // The redirected value is decoded into a value of ASN.1 type Seq.
 // Same input value as in test 8.
 testcase tc_asn_value_redirect() runs on CT
@@ -80,7 +80,7 @@ testcase tc_asn_value_redirect() runs on CT
   }
 }
 
-// Test 17 (RT2 only).
+// Test 18 (RT2 only).
 // The redirected value is decoded using the PER coder.
 // Same input value as in test 11.
 testcase tc_per_value_redirect() runs on CT