diff --git a/libs/vkd3d-shader/d3dbc.c b/libs/vkd3d-shader/d3dbc.c
index ace7694a..971db6b3 100644
--- a/libs/vkd3d-shader/d3dbc.c
+++ b/libs/vkd3d-shader/d3dbc.c
@@ -1517,6 +1517,7 @@ D3DXPARAMETER_CLASS hlsl_sm1_class(const struct hlsl_type *type)
         case HLSL_CLASS_STRING:
         case HLSL_CLASS_TEXTURE:
             return D3DXPC_OBJECT;
+        case HLSL_CLASS_EFFECT_GROUP:
         case HLSL_CLASS_UAV:
         case HLSL_CLASS_VOID:
             break;
@@ -1614,6 +1615,7 @@ D3DXPARAMETER_TYPE hlsl_sm1_base_type(const struct hlsl_type *type)
         case HLSL_CLASS_STRING:
             return D3DXPT_STRING;
 
+        case HLSL_CLASS_EFFECT_GROUP:
         case HLSL_CLASS_UAV:
         case HLSL_CLASS_VOID:
             break;
diff --git a/libs/vkd3d-shader/fx.c b/libs/vkd3d-shader/fx.c
index 98443797..d2218a50 100644
--- a/libs/vkd3d-shader/fx.c
+++ b/libs/vkd3d-shader/fx.c
@@ -437,6 +437,7 @@ static uint32_t write_fx_4_type(const struct hlsl_type *type, struct fx_write_co
             break;
 
         case HLSL_CLASS_ARRAY:
+        case HLSL_CLASS_EFFECT_GROUP:
             vkd3d_unreachable();
 
         case HLSL_CLASS_SAMPLER:
@@ -618,7 +619,7 @@ static void write_groups(struct fx_write_context *fx)
     {
         const struct hlsl_type *type = var->data_type;
 
-        if (type->base_type == HLSL_TYPE_EFFECT_GROUP)
+        if (type->class == HLSL_CLASS_EFFECT_GROUP)
             write_group(var, fx);
     }
 }
@@ -834,6 +835,10 @@ static bool is_type_supported_fx_2(struct hlsl_ctx *ctx, const struct hlsl_type
         case HLSL_CLASS_UAV:
         case HLSL_CLASS_VOID:
             return false;
+
+        case HLSL_CLASS_EFFECT_GROUP:
+            /* This cannot appear as an extern variable. */
+            break;
     }
 
     vkd3d_unreachable();
diff --git a/libs/vkd3d-shader/hlsl.c b/libs/vkd3d-shader/hlsl.c
index 5dd80ff1..a835c185 100644
--- a/libs/vkd3d-shader/hlsl.c
+++ b/libs/vkd3d-shader/hlsl.c
@@ -363,6 +363,7 @@ static void hlsl_type_calculate_reg_size(struct hlsl_ctx *ctx, struct hlsl_type
             type->reg_size[HLSL_REGSET_UAVS] = 1;
             break;
 
+        case HLSL_CLASS_EFFECT_GROUP:
         case HLSL_CLASS_OBJECT:
         case HLSL_CLASS_STRING:
         case HLSL_CLASS_VOID:
@@ -439,6 +440,7 @@ static bool type_is_single_component(const struct hlsl_type *type)
         case HLSL_CLASS_ARRAY:
             return false;
 
+        case HLSL_CLASS_EFFECT_GROUP:
         case HLSL_CLASS_VOID:
             break;
     }
@@ -569,6 +571,7 @@ unsigned int hlsl_type_get_component_offset(struct hlsl_ctx *ctx, struct hlsl_ty
                 assert(idx == 0);
                 break;
 
+            case HLSL_CLASS_EFFECT_GROUP:
             case HLSL_CLASS_VOID:
                 vkd3d_unreachable();
         }
@@ -941,6 +944,7 @@ unsigned int hlsl_type_component_count(const struct hlsl_type *type)
         case HLSL_CLASS_UAV:
             return 1;
 
+        case HLSL_CLASS_EFFECT_GROUP:
         case HLSL_CLASS_VOID:
             break;
     }
@@ -2355,6 +2359,7 @@ struct vkd3d_string_buffer *hlsl_type_to_string(struct hlsl_ctx *ctx, const stru
             }
             return string;
 
+        case HLSL_CLASS_EFFECT_GROUP:
         case HLSL_CLASS_OBJECT:
         case HLSL_CLASS_SAMPLER:
         case HLSL_CLASS_STRING:
@@ -3533,7 +3538,6 @@ static void declare_predefined_types(struct hlsl_ctx *ctx)
         {"dword",           HLSL_CLASS_SCALAR, HLSL_TYPE_UINT,          1, 1},
         {"vector",          HLSL_CLASS_VECTOR, HLSL_TYPE_FLOAT,         4, 1},
         {"matrix",          HLSL_CLASS_MATRIX, HLSL_TYPE_FLOAT,         4, 4},
-        {"fxgroup",         HLSL_CLASS_OBJECT, HLSL_TYPE_EFFECT_GROUP,  1, 1},
         {"pass",            HLSL_CLASS_OBJECT, HLSL_TYPE_PASS,          1, 1},
         {"pixelshader",     HLSL_CLASS_OBJECT, HLSL_TYPE_PIXELSHADER,   1, 1},
         {"vertexshader",    HLSL_CLASS_OBJECT, HLSL_TYPE_VERTEXSHADER,  1, 1},
@@ -3650,6 +3654,7 @@ static void declare_predefined_types(struct hlsl_ctx *ctx)
     }
 
     ctx->builtin_types.Void = hlsl_new_simple_type(ctx, "void", HLSL_CLASS_VOID);
+    hlsl_scope_add_type(ctx->globals, hlsl_new_simple_type(ctx, "fxgroup", HLSL_CLASS_EFFECT_GROUP));
     hlsl_scope_add_type(ctx->globals, hlsl_new_simple_type(ctx, "STRING", HLSL_CLASS_STRING));
     hlsl_scope_add_type(ctx->globals, hlsl_new_simple_type(ctx, "texture", HLSL_CLASS_TEXTURE));
 
diff --git a/libs/vkd3d-shader/hlsl.h b/libs/vkd3d-shader/hlsl.h
index ba8b09d2..e38963ae 100644
--- a/libs/vkd3d-shader/hlsl.h
+++ b/libs/vkd3d-shader/hlsl.h
@@ -79,6 +79,7 @@ enum hlsl_type_class
     HLSL_CLASS_STRUCT,
     HLSL_CLASS_ARRAY,
     HLSL_CLASS_OBJECT,
+    HLSL_CLASS_EFFECT_GROUP,
     HLSL_CLASS_SAMPLER,
     HLSL_CLASS_STRING,
     HLSL_CLASS_TEXTURE,
@@ -101,7 +102,6 @@ enum hlsl_base_type
     HLSL_TYPE_RENDERTARGETVIEW,
     HLSL_TYPE_DEPTHSTENCILVIEW,
     HLSL_TYPE_TECHNIQUE,
-    HLSL_TYPE_EFFECT_GROUP,
 };
 
 enum hlsl_sampler_dim
diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c
index f6cccfe8..cba58080 100644
--- a/libs/vkd3d-shader/hlsl_codegen.c
+++ b/libs/vkd3d-shader/hlsl_codegen.c
@@ -1638,6 +1638,7 @@ static bool copy_propagation_transform_load(struct hlsl_ctx *ctx,
              * matrices yet. */
             return false;
 
+        case HLSL_CLASS_EFFECT_GROUP:
         case HLSL_CLASS_STRING:
         case HLSL_CLASS_VOID:
             vkd3d_unreachable();
diff --git a/libs/vkd3d-shader/tpf.c b/libs/vkd3d-shader/tpf.c
index 6ee06c02..9bc4e488 100644
--- a/libs/vkd3d-shader/tpf.c
+++ b/libs/vkd3d-shader/tpf.c
@@ -3006,6 +3006,7 @@ static D3D_SHADER_VARIABLE_CLASS sm4_class(const struct hlsl_type *type)
             return D3D_SVC_VECTOR;
 
         case HLSL_CLASS_ARRAY:
+        case HLSL_CLASS_EFFECT_GROUP:
         case HLSL_CLASS_STRUCT:
         case HLSL_CLASS_OBJECT:
         case HLSL_CLASS_SAMPLER: