Repository: kiali/kiali
Pull request #7918 (2024-11-12 17:33:00)

Workloads GVK support + Custom Workloads
### Describe the change

Workloads were tight to their `Kind`, which was making impossible to read those ones which are Custom and has the same Kind but different 'apiVersion'.
Now Workloads support GroupVersionKind  instead of 'type' field.

### Steps to test the PR
Install Kruise, wait until it is up.
`helm install kruise openkruise/kruise --version 1.7.2`
Install this custom DaemonSet.
```
apiVersion: apps.kruise.io/v1alpha1
kind: DaemonSet
metadata:
  name: fluentd-elasticsearch
  labels:
    k8s-app: fluentd-logging
spec:
  selector:
    matchLabels:
      name: fluentd-elasticsearch
  updateStrategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 1
  template:
    metadata:
      labels:
        name: fluentd-elasticsearch
    spec:
      tolerations:
      # these tolerations are to have the daemonset runnable on control plane nodes
      # remove them if your control plane nodes should not run pods
      - key: node-role.kubernetes.io/control-plane
        operator: Exists
        effect: NoSchedule
      - key: node-role.kubernetes.io/master
        operator: Exists
        effect: NoSchedule
      containers:
      - name: fluentd-elasticsearch
        image: quay.io/fluentd_elasticsearch/fluentd:v2.5.2
        resources:
          limits:
            memory: 200Mi
          requests:
            cpu: 100m
            memory: 200Mi
        volumeMounts:
        - name: varlog
          mountPath: /var/log
        - name: varlibdockercontainers
          mountPath: /var/lib/docker/containers
          readOnly: true
      terminationGracePeriodSeconds: 30
      volumes:
      - name: varlog
        hostPath:
          path: /var/log
      - name: varlibdockercontainers
        hostPath:
          path: /var/lib/docker/containers
```

List Workloads, the newly added DaemonSet should be listed.
Click on it.
Details page comes with disabled Action:
![Screenshot from 2024-11-15 11-33-32](https://github.com/user-attachments/assets/742414a0-b1c1-47fd-a0b9-6abfb67f03b2)


### Automation testing

Existing tests modified to support GVK.

### Issue reference
https://github.com/kiali/kiali/issues/7820


ferhoyos: Thanks @hhovsepy for the quick fixes. In the Type tooltip I would set only the GVK, no comment about it is read-only. 

What about an info message similar to the one we have in traces? The user will know at one sight why this workload has not all the information available
![image](https://github.com/user-attachments/assets/8ed7c57e-b8e1-44c5-aacb-acfaeb327b3e)

The message coould be something like: `This type of workload is not fully supported by Kiali, only limited information is available for display`
hhovsepy: thank you  @ferhoyos , much better now
hhovsepy: @nrfox thanks for the review, have approached all suggestions, removed odd GVK.String() in comparisons, added your test method.

Patch:
diff --git a/business/checkers/common/multi_match_selector_checker.go b/business/checkers/common/multi_match_selector_checker.go
index e8ce9c9de..59429ee3a 100644
--- a/business/checkers/common/multi_match_selector_checker.go
+++ b/business/checkers/common/multi_match_selector_checker.go
@@ -232,8 +232,7 @@ func (m GenericMultiMatchChecker) multiMatchSubjects() ReferenceMap {
 				if !selector.Matches(labels.Set(w.Labels)) {
 					continue
 				}
-				// TODO for now a hacky way, for a workload type we only have a Kind, will be checked on frontend side
-				workloadKey := models.BuildKey(schema.GroupVersionKind{Group: "", Version: "", Kind: w.Type}, w.Name, wls.Namespace, m.Cluster)
+				workloadKey := models.BuildKey(w.WorkloadGVK, w.Name, wls.Namespace, m.Cluster)
 				workloadSubjects.Add(workloadKey, subjectKey)
 			}
 		}
diff --git a/business/istio_config.go b/business/istio_config.go
index ae426b3f1..af8dae77d 100644
--- a/business/istio_config.go
+++ b/business/istio_config.go
@@ -482,116 +482,116 @@ func (in *IstioConfigService) GetIstioConfigDetails(ctx context.Context, cluster
 
 	getOpts := meta_v1.GetOptions{}
 
-	switch objectGVK.String() {
-	case kubernetes.DestinationRules.String():
+	switch objectGVK {
+	case kubernetes.DestinationRules:
 		istioConfigDetail.DestinationRule, err = in.userClients[cluster].Istio().NetworkingV1().DestinationRules(namespace).Get(ctx, object, getOpts)
 		if err == nil {
 			istioConfigDetail.DestinationRule.Kind = kubernetes.DestinationRules.Kind
 			istioConfigDetail.DestinationRule.APIVersion = kubernetes.DestinationRules.GroupVersion().String()
 		}
-	case kubernetes.EnvoyFilters.String():
+	case kubernetes.EnvoyFilters:
 		istioConfigDetail.EnvoyFilter, err = in.userClients[cluster].Istio().NetworkingV1alpha3().EnvoyFilters(namespace).Get(ctx, object, getOpts)
 		if err == nil {
 			istioConfigDetail.EnvoyFilter.Kind = kubernetes.EnvoyFilters.Kind
 			istioConfigDetail.EnvoyFilter.APIVersion = kubernetes.EnvoyFilters.GroupVersion().String()
 		}
-	case kubernetes.Gateways.String():
+	case kubernetes.Gateways:
 		istioConfigDetail.Gateway, err = in.userClients[cluster].Istio().NetworkingV1().Gateways(namespace).Get(ctx, object, getOpts)
 		if err == nil {
 			istioConfigDetail.Gateway.Kind = kubernetes.Gateways.Kind
 			istioConfigDetail.Gateway.APIVersion = kubernetes.Gateways.GroupVersion().String()
 		}
-	case kubernetes.K8sGateways.String():
+	case kubernetes.K8sGateways:
 		istioConfigDetail.K8sGateway, err = in.userClients[cluster].GatewayAPI().GatewayV1().Gateways(namespace).Get(ctx, object, getOpts)
 		if err == nil {
 			istioConfigDetail.K8sGateway.Kind = kubernetes.K8sGateways.Kind
 			istioConfigDetail.K8sGateway.APIVersion = kubernetes.K8sGateways.GroupVersion().String()
 		}
-	case kubernetes.K8sGRPCRoutes.String():
+	case kubernetes.K8sGRPCRoutes:
 		istioConfigDetail.K8sGRPCRoute, err = in.userClients[cluster].GatewayAPI().GatewayV1().GRPCRoutes(namespace).Get(ctx, object, getOpts)
 		if err == nil {
 			istioConfigDetail.K8sGRPCRoute.Kind = kubernetes.K8sGRPCRoutes.Kind
 			istioConfigDetail.K8sGRPCRoute.APIVersion = kubernetes.K8sGRPCRoutes.GroupVersion().String()
 		}
-	case kubernetes.K8sHTTPRoutes.String():
+	case kubernetes.K8sHTTPRoutes:
 		istioConfigDetail.K8sHTTPRoute, err = in.userClients[cluster].GatewayAPI().GatewayV1().HTTPRoutes(namespace).Get(ctx, object, getOpts)
 		if err == nil {
 			istioConfigDetail.K8sHTTPRoute.Kind = kubernetes.K8sHTTPRoutes.Kind
 			istioConfigDetail.K8sHTTPRoute.APIVersion = kubernetes.K8sHTTPRoutes.GroupVersion().String()
 		}
-	case kubernetes.K8sReferenceGrants.String():
+	case kubernetes.K8sReferenceGrants:
 		istioConfigDetail.K8sReferenceGrant, err = in.userClients[cluster].GatewayAPI().GatewayV1beta1().ReferenceGrants(namespace).Get(ctx, object, getOpts)
 		if err == nil {
 			istioConfigDetail.K8sReferenceGrant.Kind = kubernetes.K8sReferenceGrants.Kind
 			istioConfigDetail.K8sReferenceGrant.APIVersion = kubernetes.K8sReferenceGrants.GroupVersion().String()
 		}
-	case kubernetes.K8sTCPRoutes.String():
+	case kubernetes.K8sTCPRoutes:
 		istioConfigDetail.K8sTCPRoute, err = in.userClients[cluster].GatewayAPI().GatewayV1alpha2().TCPRoutes(namespace).Get(ctx, object, getOpts)
 		if err == nil {
 			istioConfigDetail.K8sTCPRoute.Kind = kubernetes.K8sTCPRoutes.Kind
 			istioConfigDetail.K8sTCPRoute.APIVersion = kubernetes.K8sTCPRoutes.GroupVersion().String()
 		}
-	case kubernetes.K8sTLSRoutes.String():
+	case kubernetes.K8sTLSRoutes:
 		istioConfigDetail.K8sTLSRoute, err = in.userClients[cluster].GatewayAPI().GatewayV1alpha2().TLSRoutes(namespace).Get(ctx, object, getOpts)
 		if err == nil {
 			istioConfigDetail.K8sTLSRoute.Kind = kubernetes.K8sTLSRoutes.Kind
 			istioConfigDetail.K8sTLSRoute.APIVersion = kubernetes.K8sTLSRoutes.GroupVersion().String()
 		}
-	case kubernetes.ServiceEntries.String():
+	case kubernetes.ServiceEntries:
 		istioConfigDetail.ServiceEntry, err = in.userClients[cluster].Istio().NetworkingV1().ServiceEntries(namespace).Get(ctx, object, getOpts)
 		if err == nil {
 			istioConfigDetail.ServiceEntry.Kind = kubernetes.ServiceEntries.Kind
 			istioConfigDetail.ServiceEntry.APIVersion = kubernetes.ServiceEntries.GroupVersion().String()
 		}
-	case kubernetes.Sidecars.String():
+	case kubernetes.Sidecars:
 		istioConfigDetail.Sidecar, err = in.userClients[cluster].Istio().NetworkingV1().Sidecars(namespace).Get(ctx, object, getOpts)
 		if err == nil {
 			istioConfigDetail.Sidecar.Kind = kubernetes.Sidecars.Kind
 			istioConfigDetail.Sidecar.APIVersion = kubernetes.Sidecars.GroupVersion().String()
 		}
-	case kubernetes.VirtualServices.String():
+	case kubernetes.VirtualServices:
 		istioConfigDetail.VirtualService, err = in.userClients[cluster].Istio().NetworkingV1().VirtualServices(namespace).Get(ctx, object, getOpts)
 		if err == nil {
 			istioConfigDetail.VirtualService.Kind = kubernetes.VirtualServices.Kind
 			istioConfigDetail.VirtualService.APIVersion = kubernetes.VirtualServices.GroupVersion().String()
 		}
-	case kubernetes.WorkloadEntries.String():
+	case kubernetes.WorkloadEntries:
 		istioConfigDetail.WorkloadEntry, err = in.userClients[cluster].Istio().NetworkingV1().WorkloadEntries(namespace).Get(ctx, object, getOpts)
 		if err == nil {
 			istioConfigDetail.WorkloadEntry.Kind = kubernetes.WorkloadEntries.Kind
 			istioConfigDetail.WorkloadEntry.APIVersion = kubernetes.WorkloadEntries.GroupVersion().String()
 		}
-	case kubernetes.WorkloadGroups.String():
+	case kubernetes.WorkloadGroups:
 		istioConfigDetail.WorkloadGroup, err = in.userClients[cluster].Istio().NetworkingV1().WorkloadGroups(namespace).Get(ctx, object, getOpts)
 		if err == nil {
 			istioConfigDetail.WorkloadGroup.Kind = kubernetes.WorkloadGroups.Kind
 			istioConfigDetail.WorkloadGroup.APIVersion = kubernetes.WorkloadGroups.GroupVersion().String()
 		}
-	case kubernetes.WasmPlugins.String():
+	case kubernetes.WasmPlugins:
 		istioConfigDetail.WasmPlugin, err = in.userClients[cluster].Istio().ExtensionsV1alpha1().WasmPlugins(namespace).Get(ctx, object, getOpts)
 		if err == nil {
 			istioConfigDetail.WasmPlugin.Kind = kubernetes.WasmPlugins.Kind
 			istioConfigDetail.WasmPlugin.APIVersion = kubernetes.WasmPlugins.GroupVersion().String()
 		}
-	case kubernetes.Telemetries.String():
+	case kubernetes.Telemetries:
 		istioConfigDetail.Telemetry, err = in.userClients[cluster].Istio().TelemetryV1().Telemetries(namespace).Get(ctx, object, getOpts)
 		if err == nil {
 			istioConfigDetail.Telemetry.Kind = kubernetes.Telemetries.Kind
 			istioConfigDetail.Telemetry.APIVersion = kubernetes.Telemetries.GroupVersion().String()
 		}
-	case kubernetes.AuthorizationPolicies.String():
+	case kubernetes.AuthorizationPolicies:
 		istioConfigDetail.AuthorizationPolicy, err = in.userClients[cluster].Istio().SecurityV1().AuthorizationPolicies(namespace).Get(ctx, object, getOpts)
 		if err == nil {
 			istioConfigDetail.AuthorizationPolicy.Kind = kubernetes.AuthorizationPolicies.Kind
 			istioConfigDetail.AuthorizationPolicy.APIVersion = kubernetes.AuthorizationPolicies.GroupVersion().String()
 		}
-	case kubernetes.PeerAuthentications.String():
+	case kubernetes.PeerAuthentications:
 		istioConfigDetail.PeerAuthentication, err = in.userClients[cluster].Istio().SecurityV1().PeerAuthentications(namespace).Get(ctx, object, getOpts)
 		if err == nil {
 			istioConfigDetail.PeerAuthentication.Kind = kubernetes.PeerAuthentications.Kind
 			istioConfigDetail.PeerAuthentication.APIVersion = kubernetes.PeerAuthentications.GroupVersion().String()
 		}
-	case kubernetes.RequestAuthentications.String():
+	case kubernetes.RequestAuthentications:
 		istioConfigDetail.RequestAuthentication, err = in.userClients[cluster].Istio().SecurityV1().RequestAuthentications(namespace).Get(ctx, object, getOpts)
 		if err == nil {
 			istioConfigDetail.RequestAuthentication.Kind = kubernetes.RequestAuthentications.Kind
@@ -630,44 +630,44 @@ func (in *IstioConfigService) DeleteIstioConfigDetail(ctx context.Context, clust
 		return err
 	}
 
-	switch resourceType.String() {
-	case kubernetes.DestinationRules.String():
+	switch resourceType {
+	case kubernetes.DestinationRules:
 		err = userClient.Istio().NetworkingV1().DestinationRules(namespace).Delete(ctx, name, delOpts)
-	case kubernetes.EnvoyFilters.String():
+	case kubernetes.EnvoyFilters:
 		err = userClient.Istio().NetworkingV1alpha3().EnvoyFilters(namespace).Delete(ctx, name, delOpts)
-	case kubernetes.Gateways.String():
+	case kubernetes.Gateways:
 		err = userClient.Istio().NetworkingV1().Gateways(namespace).Delete(ctx, name, delOpts)
-	case kubernetes.K8sGateways.String():
+	case kubernetes.K8sGateways:
 		err = userClient.GatewayAPI().GatewayV1().Gateways(namespace).Delete(ctx, name, delOpts)
-	case kubernetes.K8sGRPCRoutes.String():
+	case kubernetes.K8sGRPCRoutes:
 		err = userClient.GatewayAPI().GatewayV1().GRPCRoutes(namespace).Delete(ctx, name, delOpts)
-	case kubernetes.K8sHTTPRoutes.String():
+	case kubernetes.K8sHTTPRoutes:
 		err = userClient.GatewayAPI().GatewayV1().HTTPRoutes(namespace).Delete(ctx, name, delOpts)
-	case kubernetes.K8sReferenceGrants.String():
+	case kubernetes.K8sReferenceGrants:
 		err = userClient.GatewayAPI().GatewayV1beta1().ReferenceGrants(namespace).Delete(ctx, name, delOpts)
-	case kubernetes.K8sTCPRoutes.String():
+	case kubernetes.K8sTCPRoutes:
 		err = userClient.GatewayAPI().GatewayV1alpha2().TCPRoutes(namespace).Delete(ctx, name, delOpts)
-	case kubernetes.K8sTLSRoutes.String():
+	case kubernetes.K8sTLSRoutes:
 		err = userClient.GatewayAPI().GatewayV1alpha2().TLSRoutes(namespace).Delete(ctx, name, delOpts)
-	case kubernetes.ServiceEntries.String():
+	case kubernetes.ServiceEntries:
 		err = userClient.Istio().NetworkingV1().ServiceEntries(namespace).Delete(ctx, name, delOpts)
-	case kubernetes.Sidecars.String():
+	case kubernetes.Sidecars:
 		err = userClient.Istio().NetworkingV1().Sidecars(namespace).Delete(ctx, name, delOpts)
-	case kubernetes.VirtualServices.String():
+	case kubernetes.VirtualServices:
 		err = userClient.Istio().NetworkingV1().VirtualServices(namespace).Delete(ctx, name, delOpts)
-	case kubernetes.WorkloadEntries.String():
+	case kubernetes.WorkloadEntries:
 		err = userClient.Istio().NetworkingV1().WorkloadEntries(namespace).Delete(ctx, name, delOpts)
-	case kubernetes.WorkloadGroups.String():
+	case kubernetes.WorkloadGroups:
 		err = userClient.Istio().NetworkingV1().WorkloadGroups(namespace).Delete(ctx, name, delOpts)
-	case kubernetes.AuthorizationPolicies.String():
+	case kubernetes.AuthorizationPolicies:
 		err = userClient.Istio().SecurityV1().AuthorizationPolicies(namespace).Delete(ctx, name, delOpts)
-	case kubernetes.PeerAuthentications.String():
+	case kubernetes.PeerAuthentications:
 		err = userClient.Istio().SecurityV1().PeerAuthentications(namespace).Delete(ctx, name, delOpts)
-	case kubernetes.RequestAuthentications.String():
+	case kubernetes.RequestAuthentications:
 		err = userClient.Istio().SecurityV1().RequestAuthentications(namespace).Delete(ctx, name, delOpts)
-	case kubernetes.WasmPlugins.String():
+	case kubernetes.WasmPlugins:
 		err = userClient.Istio().ExtensionsV1alpha1().WasmPlugins(namespace).Delete(ctx, name, delOpts)
-	case kubernetes.Telemetries.String():
+	case kubernetes.Telemetries:
 		err = userClient.Istio().TelemetryV1().Telemetries(namespace).Delete(ctx, name, delOpts)
 	default:
 		err = fmt.Errorf("object type not found: %v", resourceType)
diff --git a/business/istio_validations.go b/business/istio_validations.go
index d9e07fb30..59a6a78c6 100644
--- a/business/istio_validations.go
+++ b/business/istio_validations.go
@@ -280,32 +280,32 @@ func (in *IstioValidationsService) GetIstioObjectValidations(ctx context.Context
 
 	noServiceChecker := checkers.NoServiceChecker{Cluster: cluster, Namespaces: namespaces, IstioConfigList: &istioConfigList, WorkloadsPerNamespace: workloadsPerNamespace, AuthorizationDetails: &rbacDetails, RegistryServices: registryServices, PolicyAllowAny: in.isPolicyAllowAny()}
 
-	switch objectGVK.String() {
-	case kubernetes.Gateways.String():
+	switch objectGVK {
+	case kubernetes.Gateways:
 		objectCheckers = []checkers.ObjectChecker{
 			checkers.GatewayChecker{Cluster: cluster, Gateways: istioConfigList.Gateways, WorkloadsPerNamespace: workloadsPerNamespace, IsGatewayToNamespace: in.isGatewayToNamespace()},
 		}
 		referenceChecker = references.GatewayReferences{Gateways: istioConfigList.Gateways, VirtualServices: istioConfigList.VirtualServices, WorkloadsPerNamespace: workloadsPerNamespace}
-	case kubernetes.VirtualServices.String():
+	case kubernetes.VirtualServices:
 		virtualServiceChecker := checkers.VirtualServiceChecker{Cluster: cluster, Namespaces: namespaces, VirtualServices: istioConfigList.VirtualServices, DestinationRules: istioConfigList.DestinationRules}
 		objectCheckers = []checkers.ObjectChecker{noServiceChecker, virtualServiceChecker}
 		referenceChecker = references.VirtualServiceReferences{Namespace: namespace, Namespaces: namespaces, VirtualServices: istioConfigList.VirtualServices, DestinationRules: istioConfigList.DestinationRules, AuthorizationPolicies: rbacDetails.AuthorizationPolicies}
-	case kubernetes.DestinationRules.String():
+	case kubernetes.DestinationRules:
 		destinationRulesChecker := checkers.DestinationRulesChecker{Cluster: cluster, Namespaces: namespaces, DestinationRules: istioConfigList.DestinationRules, MTLSDetails: mtlsDetails, ServiceEntries: istioConfigList.ServiceEntries}
 		objectCheckers = []checkers.ObjectChecker{noServiceChecker, destinationRulesChecker}
 		referenceChecker = references.DestinationRuleReferences{Namespace: namespace, Namespaces: namespaces, DestinationRules: istioConfigList.DestinationRules, VirtualServices: istioConfigList.VirtualServices, WorkloadsPerNamespace: workloadsPerNamespace, ServiceEntries: istioConfigList.ServiceEntries, RegistryServices: registryServices}
-	case kubernetes.ServiceEntries.String():
+	case kubernetes.ServiceEntries:
 		serviceEntryChecker := checkers.ServiceEntryChecker{Cluster: cluster, ServiceEntries: istioConfigList.ServiceEntries, Namespaces: namespaces, WorkloadEntries: istioConfigList.WorkloadEntries}
 		objectCheckers = []checkers.ObjectChecker{serviceEntryChecker}
 		referenceChecker = references.ServiceEntryReferences{AuthorizationPolicies: rbacDetails.AuthorizationPolicies, Namespace: namespace, Namespaces: namespaces, DestinationRules: istioConfigList.DestinationRules, ServiceEntries: istioConfigList.ServiceEntries, Sidecars: istioConfigList.Sidecars, RegistryServices: registryServices}
-	case kubernetes.Sidecars.String():
+	case kubernetes.Sidecars:
 		sidecarsChecker := checkers.SidecarChecker{
 			Cluster: cluster, Sidecars: istioConfigList.Sidecars, Namespaces: namespaces,
 			WorkloadsPerNamespace: workloadsPerNamespace, ServiceEntries: istioConfigList.ServiceEntries, RegistryServices: registryServices,
 		}
 		objectCheckers = []checkers.ObjectChecker{sidecarsChecker}
 		referenceChecker = references.SidecarReferences{Sidecars: istioConfigList.Sidecars, Namespace: namespace, Namespaces: namespaces, ServiceEntries: istioConfigList.ServiceEntries, RegistryServices: registryServices, WorkloadsPerNamespace: workloadsPerNamespace}
-	case kubernetes.AuthorizationPolicies.String():
+	case kubernetes.AuthorizationPolicies:
 		authPoliciesChecker := checkers.AuthorizationPolicyChecker{
 			AuthorizationPolicies: rbacDetails.AuthorizationPolicies,
 			Cluster:               cluster, Namespaces: namespaces, ServiceEntries: istioConfigList.ServiceEntries, ServiceAccounts: serviceAccounts,
@@ -313,46 +313,46 @@ func (in *IstioValidationsService) GetIstioObjectValidations(ctx context.Context
 		}
 		objectCheckers = []checkers.ObjectChecker{authPoliciesChecker}
 		referenceChecker = references.AuthorizationPolicyReferences{AuthorizationPolicies: rbacDetails.AuthorizationPolicies, Namespace: namespace, Namespaces: namespaces, VirtualServices: istioConfigList.VirtualServices, ServiceEntries: istioConfigList.ServiceEntries, RegistryServices: registryServices, WorkloadsPerNamespace: workloadsPerNamespace}
-	case kubernetes.PeerAuthentications.String():
+	case kubernetes.PeerAuthentications:
 		// Validations on PeerAuthentications
 		peerAuthnChecker := checkers.PeerAuthenticationChecker{Cluster: cluster, PeerAuthentications: mtlsDetails.PeerAuthentications, MTLSDetails: mtlsDetails, WorkloadsPerNamespace: workloadsPerNamespace}
 		objectCheckers = []checkers.ObjectChecker{peerAuthnChecker}
 		referenceChecker = references.PeerAuthReferences{MTLSDetails: mtlsDetails, WorkloadsPerNamespace: workloadsPerNamespace}
-	case kubernetes.WorkloadEntries.String():
+	case kubernetes.WorkloadEntries:
 		// Validation on WorkloadEntries are not yet in place
-	case kubernetes.WorkloadGroups.String():
+	case kubernetes.WorkloadGroups:
 		// Validation on WorkloadGroups are not yet in place
-	case kubernetes.RequestAuthentications.String():
+	case kubernetes.RequestAuthentications:
 		// Validation on RequestAuthentications are not yet in place
 		requestAuthnChecker := checkers.RequestAuthenticationChecker{Cluster: cluster, RequestAuthentications: istioConfigList.RequestAuthentications, WorkloadsPerNamespace: workloadsPerNamespace}
 		objectCheckers = []checkers.ObjectChecker{requestAuthnChecker}
-	case kubernetes.EnvoyFilters.String():
+	case kubernetes.EnvoyFilters:
 		// Validation on EnvoyFilters are not yet in place
-	case kubernetes.WasmPlugins.String():
+	case kubernetes.WasmPlugins:
 		// Validation on WasmPlugins is not expected
-	case kubernetes.Telemetries.String():
+	case kubernetes.Telemetries:
 		// Validation on Telemetries is not expected
-	case kubernetes.K8sGateways.String():
+	case kubernetes.K8sGateways:
 		// Validations on K8sGateways
 		objectCheckers = []checkers.ObjectChecker{
 			checkers.K8sGatewayChecker{Cluster: cluster, K8sGateways: istioConfigList.K8sGateways, GatewayClasses: in.istioConfig.GatewayAPIClasses(cluster)},
 		}
 		referenceChecker = references.K8sGatewayReferences{K8sGateways: istioConfigList.K8sGateways, K8sHTTPRoutes: istioConfigList.K8sHTTPRoutes, K8sGRPCRoutes: istioConfigList.K8sGRPCRoutes}
-	case kubernetes.K8sGRPCRoutes.String():
+	case kubernetes.K8sGRPCRoutes:
 		grpcRouteChecker := checkers.K8sGRPCRouteChecker{Cluster: cluster, K8sGRPCRoutes: istioConfigList.K8sGRPCRoutes, K8sGateways: istioConfigList.K8sGateways, K8sReferenceGrants: istioConfigList.K8sReferenceGrants, Namespaces: namespaces, RegistryServices: registryServices}
 		objectCheckers = []checkers.ObjectChecker{noServiceChecker, grpcRouteChecker}
 		referenceChecker = references.K8sGRPCRouteReferences{K8sGRPCRoutes: istioConfigList.K8sGRPCRoutes, Namespaces: namespaces, K8sReferenceGrants: istioConfigList.K8sReferenceGrants}
-	case kubernetes.K8sHTTPRoutes.String():
+	case kubernetes.K8sHTTPRoutes:
 		httpRouteChecker := checkers.K8sHTTPRouteChecker{Cluster: cluster, K8sHTTPRoutes: istioConfigList.K8sHTTPRoutes, K8sGateways: istioConfigList.K8sGateways, K8sReferenceGrants: istioConfigList.K8sReferenceGrants, Namespaces: namespaces, RegistryServices: registryServices}
 		objectCheckers = []checkers.ObjectChecker{noServiceChecker, httpRouteChecker}
 		referenceChecker = references.K8sHTTPRouteReferences{K8sHTTPRoutes: istioConfigList.K8sHTTPRoutes, Namespaces: namespaces, K8sReferenceGrants: istioConfigList.K8sReferenceGrants}
-	case kubernetes.K8sReferenceGrants.String():
+	case kubernetes.K8sReferenceGrants:
 		objectCheckers = []checkers.ObjectChecker{
 			checkers.K8sReferenceGrantChecker{Cluster: cluster, K8sReferenceGrants: istioConfigList.K8sReferenceGrants, Namespaces: namespaces},
 		}
-	case kubernetes.K8sTCPRoutes.String():
+	case kubernetes.K8sTCPRoutes:
 		// Validation on K8sTCPRoutes is not expected
-	case kubernetes.K8sTLSRoutes.String():
+	case kubernetes.K8sTLSRoutes:
 		// Validation on K8sTLSRoutes is not expected
 	default:
 		err = fmt.Errorf("object type not found: %v", objectGVK.String())
diff --git a/business/workloads.go b/business/workloads.go
index fa1f423bd..08845a99d 100644
--- a/business/workloads.go
+++ b/business/workloads.go
@@ -23,6 +23,7 @@ import (
 	"k8s.io/apimachinery/pkg/api/errors"
 	meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/labels"
+	"k8s.io/apimachinery/pkg/runtime/schema"
 
 	"github.com/kiali/kiali/business/checkers"
 	"github.com/kiali/kiali/config"
@@ -77,7 +78,7 @@ type WorkloadCriteria struct {
 	Cluster               string
 	Namespace             string
 	WorkloadName          string
-	WorkloadType          string
+	WorkloadGVK           schema.GroupVersionKind
 	IncludeIstioResources bool
 	IncludeServices       bool
 	IncludeHealth         bool
@@ -399,7 +400,7 @@ func (in *WorkloadService) GetWorkload(ctx context.Context, criteria WorkloadCri
 		observability.Attribute("cluster", criteria.Cluster),
 		observability.Attribute("namespace", criteria.Namespace),
 		observability.Attribute("workloadName", criteria.WorkloadName),
-		observability.Attribute("workloadType", criteria.WorkloadType),
+		observability.Attribute("workloadType", criteria.WorkloadGVK.String()),
 		observability.Attribute("includeServices", criteria.IncludeServices),
 		observability.Attribute("rateInterval", criteria.RateInterval),
 		observability.Attribute("queryTime", criteria.QueryTime),
@@ -452,14 +453,15 @@ func (in *WorkloadService) GetWorkload(ctx context.Context, criteria WorkloadCri
 	return workload, nil
 }
 
-func (in *WorkloadService) UpdateWorkload(ctx context.Context, cluster string, namespace string, workloadName string, workloadType string, includeServices bool, jsonPatch string, patchType string) (*models.Workload, error) {
+func (in *WorkloadService) UpdateWorkload(ctx context.Context, cluster string, namespace string, workloadName string, workloadGVK schema.GroupVersionKind, includeServices bool, jsonPatch string, patchType string) (*models.Workload, error) {
 	var end observability.EndFunc
 	ctx, end = observability.StartSpan(ctx, "UpdateWorkload",
 		observability.Attribute("package", "business"),
 		observability.Attribute("cluster", cluster),
 		observability.Attribute("namespace", namespace),
 		observability.Attribute("workloadName", workloadName),
-		observability.Attribute("workloadType", workloadType),
+		observability.Attribute("workloadKind", workloadGVK.Kind),
+		observability.Attribute("workloadGroupVersion", workloadGVK.GroupVersion().String()),
 		observability.Attribute("includeServices", includeServices),
 		observability.Attribute("jsonPatch", jsonPatch),
 		observability.Attribute("patchType", patchType),
@@ -467,7 +469,7 @@ func (in *WorkloadService) UpdateWorkload(ctx context.Context, cluster string, n
 	defer end()
 
 	// Identify controller and apply patch to workload
-	err := in.updateWorkload(ctx, cluster, namespace, workloadName, workloadType, jsonPatch, patchType)
+	err := in.updateWorkload(ctx, cluster, namespace, workloadName, workloadGVK, jsonPatch, patchType)
 	if err != nil {
 		return nil, err
 	}
@@ -482,7 +484,7 @@ func (in *WorkloadService) UpdateWorkload(ctx context.Context, cluster string, n
 	cache.Refresh(namespace)
 
 	// After the update we fetch the whole workload
-	return in.GetWorkload(ctx, WorkloadCriteria{Cluster: cluster, Namespace: namespace, WorkloadName: workloadName, WorkloadType: workloadType, IncludeServices: includeServices})
+	return in.GetWorkload(ctx, WorkloadCriteria{Cluster: cluster, Namespace: namespace, WorkloadName: workloadName, WorkloadGVK: workloadGVK, IncludeServices: includeServices})
 }
 
 func (in *WorkloadService) GetPod(cluster, namespace, name string) (*models.Pod, error) {
@@ -918,19 +920,24 @@ func (in *WorkloadService) fetchWorkloadsFromCluster(ctx context.Context, cluste
 		return ws, err
 	}
 
-	// Key: name of controller; Value: type of controller
-	controllers := map[string]string{}
+	// Key: name of controller; Value: GroupVersionKind of controller
+	controllers := map[string]schema.GroupVersionKind{}
 
 	// Find controllers from pods
 	for _, pod := range pods {
 		if len(pod.OwnerReferences) != 0 {
 			for _, ref := range pod.OwnerReferences {
+				refGV, err := schema.ParseGroupVersion(ref.APIVersion)
+				if err != nil {
+					log.Errorf("could not parse OwnerReference api version %q: %v", ref.APIVersion, err)
+					continue
+				}
 				if ref.Controller != nil && *ref.Controller && in.isWorkloadIncluded(ref.Kind) {
 					if _, exist := controllers[ref.Name]; !exist {
-						controllers[ref.Name] = ref.Kind
+						controllers[ref.Name] = refGV.WithKind(ref.Kind)
 					} else {
-						if controllers[ref.Name] != ref.Kind {
-							controllers[ref.Name] = controllerPriority(controllers[ref.Name], ref.Kind)
+						if controllers[ref.Name] != refGV.WithKind(ref.Kind) {
+							controllers[ref.Name] = refGV.WithKind(controllerPriority(controllers[ref.Name].Kind, ref.Kind))
 						}
 					}
 				}
@@ -938,7 +945,7 @@ func (in *WorkloadService) fetchWorkloadsFromCluster(ctx context.Context, cluste
 		} else {
 			if _, exist := controllers[pod.Name]; !exist {
 				// Pod without controller
-				controllers[pod.Name] = "Pod"
+				controllers[pod.Name] = kubernetes.Pods
 			}
 		}
 	}
@@ -946,8 +953,8 @@ func (in *WorkloadService) fetchWorkloadsFromCluster(ctx context.Context, cluste
 	// Resolve ReplicaSets from Deployments
 	// Resolve ReplicationControllers from DeploymentConfigs
 	// Resolve Jobs from CronJobs
-	for controllerName, controllerType := range controllers {
-		if controllerType == kubernetes.ReplicaSetType {
+	for controllerName, controllerGVK := range controllers {
+		if controllerGVK == kubernetes.ReplicaSets {
 			found := false
 			iFound := -1
 			for i, rs := range repset {
@@ -960,18 +967,23 @@ func (in *WorkloadService) fetchWorkloadsFromCluster(ctx context.Context, cluste
 			if found && len(repset[iFound].OwnerReferences) > 0 {
 				for _, ref := range repset[iFound].OwnerReferences {
 					if ref.Controller != nil && *ref.Controller {
+						refGV, err := schema.ParseGroupVersion(ref.APIVersion)
+						if err != nil {
+							log.Errorf("could not parse OwnerReference api version %q: %v", ref.APIVersion, err)
+							continue
+						}
 						if _, exist := controllers[ref.Name]; !exist {
 							// For valid owner controllers, delete the child ReplicaSet and add the parent controller,
 							// otherwise (for custom controllers), defer to the replica set.
 							if in.isWorkloadValid(ref.Kind) {
-								controllers[ref.Name] = ref.Kind
+								controllers[ref.Name] = refGV.WithKind(ref.Kind)
 								delete(controllers, controllerName)
 							} else {
 								log.Debugf("Add ReplicaSet to workload list for custom controller [%s][%s]", ref.Name, ref.Kind)
 							}
 						} else {
-							if controllers[ref.Name] != ref.Kind {
-								controllers[ref.Name] = controllerPriority(controllers[ref.Name], ref.Kind)
+							if controllers[ref.Name] != refGV.WithKind(ref.Kind) {
+								controllers[ref.Name] = refGV.WithKind(controllerPriority(controllers[ref.Name].Kind, ref.Kind))
 							}
 							delete(controllers, controllerName)
 						}
@@ -979,7 +991,7 @@ func (in *WorkloadService) fetchWorkloadsFromCluster(ctx context.Context, cluste
 				}
 			}
 		}
-		if controllerType == kubernetes.ReplicationControllerType {
+		if controllerGVK == kubernetes.ReplicationControllers {
 			found := false
 			iFound := -1
 			for i, rc := range repcon {
@@ -991,13 +1003,18 @@ func (in *WorkloadService) fetchWorkloadsFromCluster(ctx context.Context, cluste
 			}
 			if found && len(repcon[iFound].OwnerReferences) > 0 {
 				for _, ref := range repcon[iFound].OwnerReferences {
+					refGV, err := schema.ParseGroupVersion(ref.APIVersion)
+					if err != nil {
+						log.Errorf("could not parse OwnerReference api version %q: %v", ref.APIVersion, err)
+						continue
+					}
 					if ref.Controller != nil && *ref.Controller {
 						// Delete the child ReplicationController and add the parent controller
 						if _, exist := controllers[ref.Name]; !exist {
-							controllers[ref.Name] = ref.Kind
+							controllers[ref.Name] = refGV.WithKind(ref.Kind)
 						} else {
-							if controllers[ref.Name] != ref.Kind {
-								controllers[ref.Name] = controllerPriority(controllers[ref.Name], ref.Kind)
+							if controllers[ref.Name] != refGV.WithKind(ref.Kind) {
+								controllers[ref.Name] = refGV.WithKind(controllerPriority(controllers[ref.Name].Kind, ref.Kind))
 							}
 						}
 						delete(controllers, controllerName)
@@ -1005,7 +1022,7 @@ func (in *WorkloadService) fetchWorkloadsFromCluster(ctx context.Context, cluste
 				}
 			}
 		}
-		if controllerType == kubernetes.JobType {
+		if controllerGVK == kubernetes.Jobs {
 			found := false
 			iFound := -1
 			for i, jb := range jbs {
@@ -1017,13 +1034,18 @@ func (in *WorkloadService) fetchWorkloadsFromCluster(ctx context.Context, cluste
 			}
 			if found && len(jbs[iFound].OwnerReferences) > 0 {
 				for _, ref := range jbs[iFound].OwnerReferences {
+					refGV, err := schema.ParseGroupVersion(ref.APIVersion)
+					if err != nil {
+						log.Errorf("could not parse OwnerReference api version %q: %v", ref.APIVersion, err)
+						continue
+					}
 					if ref.Controller != nil && *ref.Controller {
 						// Delete the child Job and add the parent controller
 						if _, exist := controllers[ref.Name]; !exist {
-							controllers[ref.Name] = ref.Kind
+							controllers[ref.Name] = refGV.WithKind(ref.Kind)
 						} else {
-							if controllers[ref.Name] != ref.Kind {
-								controllers[ref.Name] = controllerPriority(controllers[ref.Name], ref.Kind)
+							if controllers[ref.Name] != refGV.WithKind(ref.Kind) {
+								controllers[ref.Name] = refGV.WithKind(controllerPriority(controllers[ref.Name].Kind, ref.Kind))
 							}
 						}
 						// Jobs are special as deleting CronJob parent doesn't delete children
@@ -1059,7 +1081,7 @@ func (in *WorkloadService) fetchWorkloadsFromCluster(ctx context.Context, cluste
 			selectorCheck = selector.Matches(labels.Set(d.Spec.Template.Labels))
 		}
 		if _, exist := controllers[d.Name]; !exist && selectorCheck {
-			controllers[d.Name] = "Deployment"
+			controllers[d.Name] = kubernetes.Deployments
 		}
 	}
 	for _, rs := range repset {
@@ -1068,7 +1090,7 @@ func (in *WorkloadService) fetchWorkloadsFromCluster(ctx context.Context, cluste
 			selectorCheck = selector.Matches(labels.Set(rs.Spec.Template.Labels))
 		}
 		if _, exist := controllers[rs.Name]; !exist && len(rs.OwnerReferences) == 0 && selectorCheck {
-			controllers[rs.Name] = "ReplicaSet"
+			controllers[rs.Name] = kubernetes.ReplicaSets
 		}
 	}
 	for _, dc := range depcon {
@@ -1077,7 +1099,7 @@ func (in *WorkloadService) fetchWorkloadsFromCluster(ctx context.Context, cluste
 			selectorCheck = selector.Matches(labels.Set(dc.Spec.Template.Labels))
 		}
 		if _, exist := controllers[dc.Name]; !exist && selectorCheck {
-			controllers[dc.Name] = "DeploymentConfig"
+			controllers[dc.Name] = kubernetes.DeploymentConfigs
 		}
 	}
 	for _, rc := range repcon {
@@ -1086,7 +1108,7 @@ func (in *WorkloadService) fetchWorkloadsFromCluster(ctx context.Context, cluste
 			selectorCheck = selector.Matches(labels.Set(rc.Spec.Template.Labels))
 		}
 		if _, exist := controllers[rc.Name]; !exist && len(rc.OwnerReferences) == 0 && selectorCheck {
-			controllers[rc.Name] = "ReplicationController"
+			controllers[rc.Name] = kubernetes.ReplicationControllers
 		}
 	}
 	for _, fs := range fulset {
@@ -1095,7 +1117,7 @@ func (in *WorkloadService) fetchWorkloadsFromCluster(ctx context.Context, cluste
 			selectorCheck = selector.Matches(labels.Set(fs.Spec.Template.Labels))
 		}
 		if _, exist := controllers[fs.Name]; !exist && selectorCheck {
-			controllers[fs.Name] = "StatefulSet"
+			controllers[fs.Name] = kubernetes.StatefulSets
 		}
 	}
 	for _, ds := range daeset {
@@ -1104,7 +1126,7 @@ func (in *WorkloadService) fetchWorkloadsFromCluster(ctx context.Context, cluste
 			selectorCheck = selector.Matches(labels.Set(ds.Spec.Template.Labels))
 		}
 		if _, exist := controllers[ds.Name]; !exist && selectorCheck {
-			controllers[ds.Name] = "DaemonSet"
+			controllers[ds.Name] = kubernetes.DaemonSets
 		}
 	}
 
@@ -1121,11 +1143,11 @@ func (in *WorkloadService) fetchWorkloadsFromCluster(ctx context.Context, cluste
 		}
 		w.Cluster = cluster
 		w.Namespace = namespace
-		controllerType := controllers[controllerName]
+		controllerGVK := controllers[controllerName]
 		// Flag to add a controller if it is found
 		cnFound := true
-		switch controllerType {
-		case kubernetes.DeploymentType:
+		switch controllerGVK {
+		case kubernetes.Deployments:
 			found := false
 			iFound := -1
 			for i, dp := range dep {
@@ -1143,7 +1165,7 @@ func (in *WorkloadService) fetchWorkloadsFromCluster(ctx context.Context, cluste
 				log.Errorf("Workload %s is not found as Deployment", controllerName)
 				cnFound = false
 			}
-		case kubernetes.ReplicaSetType:
+		case kubernetes.ReplicaSets:
 			found := false
 			iFound := -1
 			for i, rs := range repset {
@@ -1161,7 +1183,7 @@ func (in *WorkloadService) fetchWorkloadsFromCluster(ctx context.Context, cluste
 				log.Errorf("Workload %s is not found as ReplicaSet", controllerName)
 				cnFound = false
 			}
-		case kubernetes.ReplicationControllerType:
+		case kubernetes.ReplicationControllers:
 			found := false
 			iFound := -1
 			for i, rc := range repcon {
@@ -1179,7 +1201,7 @@ func (in *WorkloadService) fetchWorkloadsFromCluster(ctx context.Context, cluste
 				log.Errorf("Workload %s is not found as ReplicationController", controllerName)
 				cnFound = false
 			}
-		case kubernetes.DeploymentConfigType:
+		case kubernetes.DeploymentConfigs:
 			found := false
 			iFound := -1
 			for i, dc := range depcon {
@@ -1197,7 +1219,7 @@ func (in *WorkloadService) fetchWorkloadsFromCluster(ctx context.Context, cluste
 				log.Errorf("Workload %s is not found as DeploymentConfig", controllerName)
 				cnFound = false
 			}
-		case kubernetes.StatefulSetType:
+		case kubernetes.StatefulSets:
 			found := false
 			iFound := -1
 			for i, fs := range fulset {
@@ -1215,7 +1237,7 @@ func (in *WorkloadService) fetchWorkloadsFromCluster(ctx context.Context, cluste
 				log.Errorf("Workload %s is not found as StatefulSet", controllerName)
 				cnFound = false
 			}
-		case kubernetes.PodType:
+		case kubernetes.Pods:
 			found := false
 			iFound := -1
 			for i, pod := range pods {
@@ -1232,7 +1254,7 @@ func (in *WorkloadService) fetchWorkloadsFromCluster(ctx context.Context, cluste
 				log.Errorf("Workload %s is not found as Pod", controllerName)
 				cnFound = false
 			}
-		case kubernetes.JobType:
+		case kubernetes.Jobs:
 			found := false
 			iFound := -1
 			for i, jb := range jbs {
@@ -1250,7 +1272,7 @@ func (in *WorkloadService) fetchWorkloadsFromCluster(ctx context.Context, cluste
 				log.Errorf("Workload %s is not found as Job", controllerName)
 				cnFound = false
 			}
-		case kubernetes.CronJobType:
+		case kubernetes.CronJobs:
 			found := false
 			iFound := -1
 			for i, cjb := range conjbs {
@@ -1268,7 +1290,7 @@ func (in *WorkloadService) fetchWorkloadsFromCluster(ctx context.Context, cluste
 				log.Warningf("Workload %s is not found as CronJob (CronJob could be deleted but children are still in the namespace)", controllerName)
 				cnFound = false
 			}
-		case kubernetes.DaemonSetType:
+		case kubernetes.DaemonSets:
 			found := false
 			iFound := -1
 			for i, ds := range daeset {
@@ -1290,10 +1312,10 @@ func (in *WorkloadService) fetchWorkloadsFromCluster(ctx context.Context, cluste
 			// This covers the scenario of a custom controller without replicaset, controlling pods directly.
 			// Note that a custom controller with replicaset(s) will return the replicaset(s) as the workloads.
 			var cPods []core_v1.Pod
-			cPods = kubernetes.FilterPodsByController(controllerName, controllerType, pods)
+			cPods = kubernetes.FilterPodsByController(controllerName, controllerGVK, pods)
 			if len(cPods) > 0 {
-				w.ParsePods(controllerName, controllerType, cPods)
-				log.Debugf("Workload %s of type %s has no ReplicaSet as a child controller (this may be ok, but is unusual)", controllerName, controllerType)
+				w.ParsePods(controllerName, controllerGVK, cPods)
+				log.Debugf("Workload %s of type %s has no ReplicaSet as a child controller (this may be ok, but is unusual)", controllerName, controllerGVK)
 			}
 			w.SetPods(cPods)
 		}
@@ -1344,7 +1366,7 @@ func (in *WorkloadService) fetchWorkload(ctx context.Context, criteria WorkloadC
 	// Flag used for custom controllers
 	// i.e. a third party framework creates its own "Deployment" controller with extra features
 	// on this case, Kiali will collect basic info from the ReplicaSet controller
-	_, knownWorkloadType := controllerOrder[criteria.WorkloadType]
+	_, knownWorkloadType := controllerOrder[criteria.WorkloadGVK.Kind]
 
 	wg := sync.WaitGroup{}
 	wg.Add(9)
@@ -1376,7 +1398,7 @@ func (in *WorkloadService) fetchWorkload(ctx context.Context, criteria WorkloadC
 		defer wg.Done()
 		var err error
 
-		if criteria.WorkloadType != "" && criteria.WorkloadType != kubernetes.DeploymentType {
+		if criteria.WorkloadGVK.Kind != "" && criteria.WorkloadGVK != kubernetes.Deployments {
 			return
 		}
 		dep, err = kialiCache.GetDeployment(criteria.Namespace, criteria.WorkloadName)
@@ -1394,7 +1416,7 @@ func (in *WorkloadService) fetchWorkload(ctx context.Context, criteria WorkloadC
 	go func() {
 		defer wg.Done()
 
-		if criteria.WorkloadType != "" && criteria.WorkloadType != kubernetes.ReplicaSetType && knownWorkloadType {
+		if criteria.WorkloadGVK.Kind != "" && criteria.WorkloadGVK != kubernetes.ReplicaSets && knownWorkloadType {
 			return
 		}
 		var err error
@@ -1409,7 +1431,7 @@ func (in *WorkloadService) fetchWorkload(ctx context.Context, criteria WorkloadC
 	go func() {
 		defer wg.Done()
 
-		if criteria.WorkloadType != "" && criteria.WorkloadType != kubernetes.ReplicationControllerType {
+		if criteria.WorkloadGVK.Kind != "" && criteria.WorkloadGVK != kubernetes.ReplicationControllers {
 			return
 		}
 
@@ -1428,7 +1450,7 @@ func (in *WorkloadService) fetchWorkload(ctx context.Context, criteria WorkloadC
 	go func() {
 		defer wg.Done()
 
-		if criteria.WorkloadType != "" && criteria.WorkloadType != kubernetes.DeploymentConfigType {
+		if criteria.WorkloadGVK.Kind != "" && criteria.WorkloadGVK != kubernetes.DeploymentConfigs {
 			return
 		}
 
@@ -1446,7 +1468,7 @@ func (in *WorkloadService) fetchWorkload(ctx context.Context, criteria WorkloadC
 	go func() {
 		defer wg.Done()
 
-		if criteria.WorkloadType != "" && criteria.WorkloadType != kubernetes.StatefulSetType {
+		if criteria.WorkloadGVK.Kind != "" && criteria.WorkloadGVK != kubernetes.StatefulSets {
 			return
 		}
 
@@ -1463,7 +1485,7 @@ func (in *WorkloadService) fetchWorkload(ctx context.Context, criteria WorkloadC
 	go func() {
 		defer wg.Done()
 
-		if criteria.WorkloadType != "" && criteria.WorkloadType != kubernetes.CronJobType {
+		if criteria.WorkloadGVK.Kind != "" && criteria.WorkloadGVK != kubernetes.CronJobs {
 			return
 		}
 
@@ -1482,7 +1504,7 @@ func (in *WorkloadService) fetchWorkload(ctx context.Context, criteria WorkloadC
 	go func() {
 		defer wg.Done()
 
-		if criteria.WorkloadType != "" && criteria.WorkloadType != kubernetes.JobType {
+		if criteria.WorkloadGVK.Kind != "" && criteria.WorkloadGVK != kubernetes.Jobs {
 			return
 		}
 
@@ -1501,7 +1523,7 @@ func (in *WorkloadService) fetchWorkload(ctx context.Context, criteria WorkloadC
 	go func() {
 		defer wg.Done()
 
-		if criteria.WorkloadType != "" && criteria.WorkloadType != kubernetes.DaemonSetType {
+		if criteria.WorkloadGVK.Kind != "" && criteria.WorkloadGVK != kubernetes.DaemonSets {
 			return
 		}
 
@@ -1520,19 +1542,24 @@ func (in *WorkloadService) fetchWorkload(ctx context.Context, criteria WorkloadC
 		return wl, err
 	}
 
-	// Key: name of controller; Value: type of controller
-	controllers := map[string]string{}
+	// Key: name of controller; Value: GVK of controller
+	controllers := map[string]schema.GroupVersionKind{}
 
 	// Find controllers from pods
 	for _, pod := range pods {
 		if len(pod.OwnerReferences) != 0 {
 			for _, ref := range pod.OwnerReferences {
+				refGV, err := schema.ParseGroupVersion(ref.APIVersion)
+				if err != nil {
+					log.Errorf("could not parse OwnerReference api version %q: %v", ref.APIVersion, err)
+					continue
+				}
 				if ref.Controller != nil && *ref.Controller && in.isWorkloadIncluded(ref.Kind) {
 					if _, exist := controllers[ref.Name]; !exist {
-						controllers[ref.Name] = ref.Kind
+						controllers[ref.Name] = refGV.WithKind(ref.Kind)
 					} else {
-						if controllers[ref.Name] != ref.Kind {
-							controllers[ref.Name] = controllerPriority(controllers[ref.Name], ref.Kind)
+						if controllers[ref.Name] != refGV.WithKind(ref.Kind) {
+							controllers[ref.Name] = refGV.WithKind(controllerPriority(controllers[ref.Name].String(), ref.Kind))
 						}
 					}
 				}
@@ -1540,7 +1567,7 @@ func (in *WorkloadService) fetchWorkload(ctx context.Context, criteria WorkloadC
 		} else {
 			if _, exist := controllers[pod.Name]; !exist {
 				// Pod without controller
-				controllers[pod.Name] = "Pod"
+				controllers[pod.Name] = kubernetes.Pods
 			}
 		}
 	}
@@ -1548,8 +1575,8 @@ func (in *WorkloadService) fetchWorkload(ctx context.Context, criteria WorkloadC
 	// Resolve ReplicaSets from Deployments
 	// Resolve ReplicationControllers from DeploymentConfigs
 	// Resolve Jobs from CronJobs
-	for controllerName, controllerType := range controllers {
-		if controllerType == kubernetes.ReplicaSetType {
+	for controllerName, controllerGVK := range controllers {
+		if controllerGVK == kubernetes.ReplicaSets {
 			found := false
 			iFound := -1
 			for i, rs := range repset {
@@ -1561,19 +1588,24 @@ func (in *WorkloadService) fetchWorkload(ctx context.Context, criteria WorkloadC
 			}
 			if found && len(repset[iFound].OwnerReferences) > 0 {
 				for _, ref := range repset[iFound].OwnerReferences {
+					refGV, err := schema.ParseGroupVersion(ref.APIVersion)
+					if err != nil {
+						log.Errorf("could not parse OwnerReference api version %q: %v", ref.APIVersion, err)
+						continue
+					}
 					if ref.Controller != nil && *ref.Controller {
 						// For valid owner controllers, delete the child ReplicaSet and add the parent controller,
 						// otherwise (for custom controllers), defer to the replica set.
 						if _, exist := controllers[ref.Name]; !exist {
 							if in.isWorkloadValid(ref.Kind) {
-								controllers[ref.Name] = ref.Kind
+								controllers[ref.Name] = refGV.WithKind(ref.Kind)
 								delete(controllers, controllerName)
 							} else {
 								log.Debugf("Use ReplicaSet as workload for custom controller [%s][%s]", ref.Name, ref.Kind)
 							}
 						} else {
-							if controllers[ref.Name] != ref.Kind {
-								controllers[ref.Name] = controllerPriority(controllers[ref.Name], ref.Kind)
+							if controllers[ref.Name] != refGV.WithKind(ref.Kind) {
+								controllers[ref.Name] = refGV.WithKind(controllerPriority(controllers[ref.Name].Kind, ref.Kind))
 							}
 							delete(controllers, controllerName)
 						}
@@ -1581,7 +1613,7 @@ func (in *WorkloadService) fetchWorkload(ctx context.Context, criteria WorkloadC
 				}
 			}
 		}
-		if controllerType == kubernetes.ReplicationControllerType {
+		if controllerGVK == kubernetes.ReplicationControllers {
 			found := false
 			iFound := -1
 			for i, rc := range repcon {
@@ -1593,13 +1625,18 @@ func (in *WorkloadService) fetchWorkload(ctx context.Context, criteria WorkloadC
 			}
 			if found && len(repcon[iFound].OwnerReferences) > 0 {
 				for _, ref := range repcon[iFound].OwnerReferences {
+					refGV, err := schema.ParseGroupVersion(ref.APIVersion)
+					if err != nil {
+						log.Errorf("could not parse OwnerReference api version %q: %v", ref.APIVersion, err)
+						continue
+					}
 					if ref.Controller != nil && *ref.Controller {
 						// Delete the child ReplicationController and add the parent controller
 						if _, exist := controllers[ref.Name]; !exist {
-							controllers[ref.Name] = ref.Kind
+							controllers[ref.Name] = refGV.WithKind(ref.Kind)
 						} else {
-							if controllers[ref.Name] != ref.Kind {
-								controllers[ref.Name] = controllerPriority(controllers[ref.Name], ref.Kind)
+							if controllers[ref.Name] != refGV.WithKind(ref.Kind) {
+								controllers[ref.Name] = refGV.WithKind(controllerPriority(controllers[ref.Name].String(), ref.Kind))
 							}
 						}
 						delete(controllers, controllerName)
@@ -1607,7 +1644,7 @@ func (in *WorkloadService) fetchWorkload(ctx context.Context, criteria WorkloadC
 				}
 			}
 		}
-		if controllerType == kubernetes.JobType {
+		if controllerGVK == kubernetes.Jobs {
 			found := false
 			iFound := -1
 			for i, jb := range jbs {
@@ -1619,13 +1656,18 @@ func (in *WorkloadService) fetchWorkload(ctx context.Context, criteria WorkloadC
 			}
 			if found && len(jbs[iFound].OwnerReferences) > 0 {
 				for _, ref := range jbs[iFound].OwnerReferences {
+					refGV, err := schema.ParseGroupVersion(ref.APIVersion)
+					if err != nil {
+						log.Errorf("could not parse OwnerReference api version %q: %v", ref.APIVersion, err)
+						continue
+					}
 					if ref.Controller != nil && *ref.Controller {
 						// Delete the child Job and add the parent controller
 						if _, exist := controllers[ref.Name]; !exist {
-							controllers[ref.Name] = ref.Kind
+							controllers[ref.Name] = refGV.WithKind(ref.Kind)
 						} else {
-							if controllers[ref.Name] != ref.Kind {
-								controllers[ref.Name] = controllerPriority(controllers[ref.Name], ref.Kind)
+							if controllers[ref.Name] != refGV.WithKind(ref.Kind) {
+								controllers[ref.Name] = refGV.WithKind(controllerPriority(controllers[ref.Name].String(), ref.Kind))
 							}
 						}
 						// Jobs are special as deleting CronJob parent doesn't delete children
@@ -1649,32 +1691,32 @@ func (in *WorkloadService) fetchWorkload(ctx context.Context, criteria WorkloadC
 	// Cornercase, check for controllers without pods, to show them as a workload
 	if dep != nil {
 		if _, exist := controllers[dep.Name]; !exist {
-			controllers[dep.Name] = kubernetes.DeploymentType
+			controllers[dep.Name] = kubernetes.Deployments
 		}
 	}
 	for _, rs := range repset {
 		if _, exist := controllers[rs.Name]; !exist && len(rs.OwnerReferences) == 0 {
-			controllers[rs.Name] = kubernetes.ReplicaSetType
+			controllers[rs.Name] = kubernetes.ReplicaSets
 		}
 	}
 	if depcon != nil {
 		if _, exist := controllers[depcon.Name]; !exist {
-			controllers[depcon.Name] = kubernetes.DeploymentConfigType
+			controllers[depcon.Name] = kubernetes.DeploymentConfigs
 		}
 	}
 	for _, rc := range repcon {
 		if _, exist := controllers[rc.Name]; !exist && len(rc.OwnerReferences) == 0 {
-			controllers[rc.Name] = kubernetes.ReplicationControllerType
+			controllers[rc.Name] = kubernetes.ReplicationControllers
 		}
 	}
 	if fulset != nil {
 		if _, exist := controllers[fulset.Name]; !exist {
-			controllers[fulset.Name] = kubernetes.StatefulSetType
+			controllers[fulset.Name] = kubernetes.StatefulSets
 		}
 	}
 	if ds != nil {
 		if _, exist := controllers[ds.Name]; !exist {
-			controllers[ds.Name] = kubernetes.DaemonSetType
+			controllers[ds.Name] = kubernetes.DaemonSets
 		}
 	}
 
@@ -1699,16 +1741,16 @@ func (in *WorkloadService) fetchWorkload(ctx context.Context, criteria WorkloadC
 		// For custom types: fall through to the default handler and try to get the workload definition working
 		// up from the pods or replicas sets.
 		// see https://github.com/kiali/kiali/issues/3830
-		discoveredControllerType := controllers[criteria.WorkloadName]
-		controllerType := discoveredControllerType
-		if criteria.WorkloadType != "" && discoveredControllerType != criteria.WorkloadType {
-			controllerType = criteria.WorkloadType
+		discoveredControllerGVK := controllers[criteria.WorkloadName]
+		controllerGVK := discoveredControllerGVK
+		if criteria.WorkloadGVK.Kind != "" && discoveredControllerGVK != criteria.WorkloadGVK {
+			controllerGVK = criteria.WorkloadGVK
 		}
 
 		// Handle the known types...
 		cnFound := true
-		switch controllerType {
-		case kubernetes.DeploymentType:
+		switch controllerGVK {
+		case kubernetes.Deployments:
 			if dep != nil && dep.Name == criteria.WorkloadName {
 				selector := labels.Set(dep.Spec.Template.Labels).AsSelector()
 				w.SetPods(kubernetes.FilterPodsBySelector(selector, pods))
@@ -1717,7 +1759,7 @@ func (in *WorkloadService) fetchWorkload(ctx context.Context, criteria WorkloadC
 				log.Errorf("Workload %s is not found as Deployment", criteria.WorkloadName)
 				cnFound = false
 			}
-		case kubernetes.ReplicaSetType:
+		case kubernetes.ReplicaSets:
 			found := false
 			iFound := -1
 			for i, rs := range repset {
@@ -1735,7 +1777,7 @@ func (in *WorkloadService) fetchWorkload(ctx context.Context, criteria WorkloadC
 				log.Errorf("Workload %s is not found as ReplicaSet", criteria.WorkloadName)
 				cnFound = false
 			}
-		case kubernetes.ReplicationControllerType:
+		case kubernetes.ReplicationControllers:
 			found := false
 			iFound := -1
 			for i, rc := range repcon {
@@ -1753,7 +1795,7 @@ func (in *WorkloadService) fetchWorkload(ctx context.Context, criteria WorkloadC
 				log.Errorf("Workload %s is not found as ReplicationController", criteria.WorkloadName)
 				cnFound = false
 			}
-		case kubernetes.DeploymentConfigType:
+		case kubernetes.DeploymentConfigs:
 			if depcon != nil && depcon.Name == criteria.WorkloadName {
 				selector := labels.Set(depcon.Spec.Template.Labels).AsSelector()
 				w.SetPods(kubernetes.FilterPodsBySelector(selector, pods))
@@ -1762,7 +1804,7 @@ func (in *WorkloadService) fetchWorkload(ctx context.Context, criteria WorkloadC
 				log.Errorf("Workload %s is not found as DeploymentConfig", criteria.WorkloadName)
 				cnFound = false
 			}
-		case kubernetes.StatefulSetType:
+		case kubernetes.StatefulSets:
 			if fulset != nil && fulset.Name == criteria.WorkloadName {
 				selector := labels.Set(fulset.Spec.Template.Labels).AsSelector()
 				w.SetPods(kubernetes.FilterPodsBySelector(selector, pods))
@@ -1771,7 +1813,7 @@ func (in *WorkloadService) fetchWorkload(ctx context.Context, criteria WorkloadC
 				log.Errorf("Workload %s is not found as StatefulSet", criteria.WorkloadName)
 				cnFound = false
 			}
-		case kubernetes.PodType:
+		case kubernetes.Pods:
 			found := false
 			iFound := -1
 			for i, pod := range pods {
@@ -1788,7 +1830,7 @@ func (in *WorkloadService) fetchWorkload(ctx context.Context, criteria WorkloadC
 				log.Errorf("Workload %s is not found as Pod", criteria.WorkloadName)
 				cnFound = false
 			}
-		case kubernetes.JobType:
+		case kubernetes.Jobs:
 			found := false
 			iFound := -1
 			for i, jb := range jbs {
@@ -1806,7 +1848,7 @@ func (in *WorkloadService) fetchWorkload(ctx context.Context, criteria WorkloadC
 				log.Errorf("Workload %s is not found as Job", criteria.WorkloadName)
 				cnFound = false
 			}
-		case kubernetes.CronJobType:
+		case kubernetes.CronJobs:
 			found := false
 			iFound := -1
 			for i, cjb := range conjbs {
@@ -1824,7 +1866,7 @@ func (in *WorkloadService) fetchWorkload(ctx context.Context, criteria WorkloadC
 				log.Warningf("Workload %s is not found as CronJob (CronJob could be deleted but children are still in the namespace)", criteria.WorkloadName)
 				cnFound = false
 			}
-		case kubernetes.DaemonSetType:
+		case kubernetes.DaemonSets:
 			if ds != nil && ds.Name == criteria.WorkloadName {
 				selector := labels.Set(ds.Spec.Template.Labels).AsSelector()
 				w.SetPods(kubernetes.FilterPodsBySelector(selector, pods))
@@ -1841,12 +1883,12 @@ func (in *WorkloadService) fetchWorkload(ctx context.Context, criteria WorkloadC
 			// 1. use the controller type found in the Pod resolution and ignore the unknown criteria type
 			var cPods []core_v1.Pod
 			for _, rs := range repset {
-				if discoveredControllerType == kubernetes.ReplicaSetType && criteria.WorkloadName == rs.Name {
+				if discoveredControllerGVK.Kind == kubernetes.ReplicaSetType && criteria.WorkloadName == rs.Name {
 					w.ParseReplicaSet(&rs)
 				} else {
 					rsOwnerRef := meta_v1.GetControllerOf(&rs.ObjectMeta)
-					if rsOwnerRef != nil && rsOwnerRef.Name == criteria.WorkloadName && rsOwnerRef.Kind == discoveredControllerType {
-						w.ParseReplicaSetParent(&rs, criteria.WorkloadName, discoveredControllerType)
+					if rsOwnerRef != nil && rsOwnerRef.Name == criteria.WorkloadName && rsOwnerRef.Kind == discoveredControllerGVK.Kind {
+						w.ParseReplicaSetParent(&rs, criteria.WorkloadName, discoveredControllerGVK)
 					} else {
 						continue
 					}
@@ -1862,10 +1904,10 @@ func (in *WorkloadService) fetchWorkload(ctx context.Context, criteria WorkloadC
 			// 2. If no pods we're found for a ReplicaSet type, it's possible the controller
 			//    is managing the pods itself i.e. the pod's have an owner ref directly to the controller type.
 			if len(cPods) == 0 {
-				cPods = kubernetes.FilterPodsByController(criteria.WorkloadName, discoveredControllerType, pods)
+				cPods = kubernetes.FilterPodsByController(criteria.WorkloadName, discoveredControllerGVK, pods)
 				if len(cPods) > 0 {
-					w.ParsePods(criteria.WorkloadName, discoveredControllerType, cPods)
-					log.Debugf("Workload %s of type %s has not a ReplicaSet as a child controller, it may need a revisit", criteria.WorkloadName, discoveredControllerType)
+					w.ParsePods(criteria.WorkloadName, discoveredControllerGVK, cPods)
+					log.Debugf("Workload %s of type %s has not a ReplicaSet as a child controller, it may need a revisit", criteria.WorkloadName, discoveredControllerGVK)
 				}
 			}
 
@@ -1998,7 +2040,7 @@ func (in *WorkloadService) getWaypointsForWorkload(ctx context.Context, namespac
 	for _, waypoint := range waypoints {
 		// At the moment, it is not possible to have the waypoint in a different namespace
 		// This is expected to change in future releases
-		wkd, err := in.fetchWorkload(ctx, WorkloadCriteria{Cluster: workload.Cluster, Namespace: namespace, WorkloadName: waypoint.Name, WorkloadType: ""})
+		wkd, err := in.fetchWorkload(ctx, WorkloadCriteria{Cluster: workload.Cluster, Namespace: namespace, WorkloadName: waypoint.Name, WorkloadGVK: schema.GroupVersionKind{}})
 		if err != nil {
 			log.Debugf("getWaypointsForWorkload: Error fetching workloads %s", err.Error())
 			return nil
@@ -2048,7 +2090,7 @@ func (in *WorkloadService) listWaypointWorkloads(ctx context.Context, name, clus
 	return workloadslist
 }
 
-func (in *WorkloadService) updateWorkload(ctx context.Context, cluster string, namespace string, workloadName string, workloadType string, jsonPatch string, patchType string) error {
+func (in *WorkloadService) updateWorkload(ctx context.Context, cluster string, namespace string, workloadName string, workloadGVK schema.GroupVersionKind, jsonPatch string, patchType string) error {
 	// Check if user has access to the namespace (RBAC) in cache scenarios and/or
 	// if namespace is accessible from Kiali (Deployment.AccessibleNamespaces)
 	if _, err := in.businessLayer.Namespace.GetClusterNamespace(ctx, namespace, cluster); err != nil {
@@ -2060,51 +2102,51 @@ func (in *WorkloadService) updateWorkload(ctx context.Context, cluster string, n
 		return fmt.Errorf("user client for cluster [%s] not found", cluster)
 	}
 
-	workloadTypes := []string{
-		kubernetes.DeploymentType,
-		kubernetes.ReplicaSetType,
-		kubernetes.ReplicationControllerType,
-		kubernetes.DeploymentConfigType,
-		kubernetes.StatefulSetType,
-		kubernetes.JobType,
-		kubernetes.CronJobType,
-		kubernetes.PodType,
-		kubernetes.DaemonSetType,
+	workloadGVKs := []schema.GroupVersionKind{
+		kubernetes.Deployments,
+		kubernetes.ReplicaSets,
+		kubernetes.ReplicationControllers,
+		kubernetes.DeploymentConfigs,
+		kubernetes.StatefulSets,
+		kubernetes.Jobs,
+		kubernetes.CronJobs,
+		kubernetes.Pods,
+		kubernetes.DaemonSets,
 	}
 
-	// workloadType is an optional parameter used to optimize the workload type fetch
+	// workloadGVK is an optional parameter used to optimize the workload type fetch
 	// By default workloads use only the "name" but not the pair "name,type".
-	if workloadType != "" {
+	if workloadGVK.Kind != "" {
 		found := false
-		for _, wt := range workloadTypes {
-			if workloadType == wt {
+		for _, wt := range workloadGVKs {
+			if workloadGVK.Kind == wt.Kind {
 				found = true
 				break
 			}
 		}
 		if found {
-			workloadTypes = []string{workloadType}
+			workloadGVKs = []schema.GroupVersionKind{workloadGVK}
 		}
 	}
 
 	wg := sync.WaitGroup{}
-	wg.Add(len(workloadTypes))
-	errChan := make(chan error, len(workloadTypes))
+	wg.Add(len(workloadGVKs))
+	errChan := make(chan error, len(workloadGVKs))
 
-	for _, workloadType := range workloadTypes {
-		go func(wkType string) {
+	for _, workloadGVK := range workloadGVKs {
+		go func(wkGVK schema.GroupVersionKind) {
 			defer wg.Done()
 			var err error
-			if in.isWorkloadIncluded(wkType) {
-				err = userClient.UpdateWorkload(namespace, workloadName, wkType, jsonPatch, patchType)
+			if in.isWorkloadIncluded(wkGVK.Kind) {
+				err = userClient.UpdateWorkload(namespace, workloadName, wkGVK, jsonPatch, patchType)
 			}
 			if err != nil {
 				if !errors.IsNotFound(err) {
-					log.Errorf("Error fetching %s per namespace %s and name %s: %s", wkType, namespace, workloadName, err)
+					log.Errorf("Error fetching %s per namespace %s and name %s: %s", wkGVK, namespace, workloadName, err)
 					errChan <- err
 				}
 			}
-		}(workloadType)
+		}(workloadGVK)
 	}
 
 	wg.Wait()
@@ -2160,7 +2202,7 @@ func (in *WorkloadService) GetWorkloadAppName(ctx context.Context, cluster, name
 	)
 	defer end()
 
-	wkd, err := in.fetchWorkload(ctx, WorkloadCriteria{Cluster: cluster, Namespace: namespace, WorkloadName: workload, WorkloadType: ""})
+	wkd, err := in.fetchWorkload(ctx, WorkloadCriteria{Cluster: cluster, Namespace: namespace, WorkloadName: workload, WorkloadGVK: schema.GroupVersionKind{Group: "", Version: "", Kind: ""}})
 	if err != nil {
 		return "", err
 	}
diff --git a/frontend/public/locales/zh/translation.json b/frontend/public/locales/zh/translation.json
index 46be2683a..2a121861d 100644
--- a/frontend/public/locales/zh/translation.json
+++ b/frontend/public/locales/zh/translation.json
@@ -316,6 +316,7 @@
   "This chart shows memory consumption for the istiod {{memoryMetricSource}}": "This chart shows memory consumption for the istiod {{memoryMetricSource}}",
   "This rule is not accessible.": "该规则将无法生效。",
   "This shows the meshConfig.outboundTrafficPolicy.mode setting. It controls the sidecar handling of                 requests to external services (services not defined in Istio’s internal service registry). When                 set to ALLOW_ANY the Istio proxy performs a passthrough to the unknown services. When set to REGISTRY_ONLY                 the Istio proxy blocks requets to hosts without a defined HTTP service or service entry.": "This shows the meshConfig.outboundTrafficPolicy.mode setting. It controls the sidecar handling of                 requests to external services (services not defined in Istio’s internal service registry). When                 set to ALLOW_ANY the Istio proxy performs a passthrough to the unknown services. When set to REGISTRY_ONLY                 the Istio proxy blocks requets to hosts without a defined HTTP service or service entry.",
+  "This type of workload is read-only": "This type of workload is read-only",
   "Time duration": "Time duration",
   "Time range": "Time range",
   "Time Range": "Time Range",
diff --git a/frontend/src/components/Envoy/tables/ClusterTable.tsx b/frontend/src/components/Envoy/tables/ClusterTable.tsx
index f58a90a73..4891915df 100644
--- a/frontend/src/components/Envoy/tables/ClusterTable.tsx
+++ b/frontend/src/components/Envoy/tables/ClusterTable.tsx
@@ -13,7 +13,7 @@ import { kialiStyle } from 'styles/StyleUtils';
 import { isParentKiosk } from '../../Kiosk/KioskActions';
 import { SortableTh } from 'components/Table/SimpleTable';
 import { t } from 'utils/I18nUtils';
-import { dicIstioTypeToGVK } from '../../../types/IstioConfigList';
+import { dicTypeToGVK, gvkType } from '../../../types/IstioConfigList';
 
 export class ClusterTable implements SummaryTable {
   kiosk: string;
@@ -271,7 +271,7 @@ export class ClusterTable implements SummaryTable {
               value.subset,
               value.direction,
               value.type,
-              istioConfigLink(value.destination_rule, dicIstioTypeToGVK['DestinationRule'])
+              istioConfigLink(value.destination_rule, dicTypeToGVK[gvkType.DestinationRule])
             ]
           };
         }
diff --git a/frontend/src/components/Envoy/tables/RouteTable.tsx b/frontend/src/components/Envoy/tables/RouteTable.tsx
index 627f0d33a..d5ed1a331 100644
--- a/frontend/src/components/Envoy/tables/RouteTable.tsx
+++ b/frontend/src/components/Envoy/tables/RouteTable.tsx
@@ -12,7 +12,7 @@ import { KialiIcon } from 'config/KialiIcon';
 import { kialiStyle } from 'styles/StyleUtils';
 import { isParentKiosk } from '../../Kiosk/KioskActions';
 import { SortableTh } from 'components/Table/SimpleTable';
-import { dicIstioTypeToGVK } from '../../../types/IstioConfigList';
+import { dicTypeToGVK, gvkType } from '../../../types/IstioConfigList';
 
 export class RouteTable implements SummaryTable {
   kiosk: string;
@@ -187,7 +187,7 @@ export class RouteTable implements SummaryTable {
               summary.name,
               serviceLink(summary.domains, this.namespaces, this.namespace, true, parentKiosk),
               summary.match,
-              istioConfigLink(summary.virtual_service, dicIstioTypeToGVK['VirtualService'])
+              istioConfigLink(summary.virtual_service, dicTypeToGVK[gvkType.VirtualService])
             ]
           };
         }
diff --git a/frontend/src/components/IstioWizards/ServiceWizard.tsx b/frontend/src/components/IstioWizards/ServiceWizard.tsx
index d23dd0d3c..5204a03cf 100644
--- a/frontend/src/components/IstioWizards/ServiceWizard.tsx
+++ b/frontend/src/components/IstioWizards/ServiceWizard.tsx
@@ -73,7 +73,7 @@ import { ConfigPreviewItem, IstioConfigPreview } from 'components/IstioConfigPre
 import { KialiIcon } from '../../config/KialiIcon';
 import { ApiResponse } from 'types/Api';
 import { t } from 'utils/I18nUtils';
-import { dicIstioTypeToGVK } from '../../types/IstioConfigList';
+import { dicTypeToGVK, gvkType } from '../../types/IstioConfigList';
 import { getGVKTypeString } from '../../utils/IstioConfigUtils';
 
 const emptyServiceWizardState = (fqdnServiceName: string): ServiceWizardState => {
@@ -371,7 +371,7 @@ export class ServiceWizard extends React.Component<ServiceWizardProps, ServiceWi
           promises.push(
             API.createIstioConfigDetail(
               this.props.namespace,
-              dicIstioTypeToGVK['Gateway'],
+              dicTypeToGVK[gvkType.Gateway],
               JSON.stringify(gw),
               this.props.cluster
             )
@@ -382,7 +382,7 @@ export class ServiceWizard extends React.Component<ServiceWizardProps, ServiceWi
           promises.push(
             API.createIstioConfigDetail(
               this.props.namespace,
-              dicIstioTypeToGVK['K8sGateway'],
+              dicTypeToGVK[gvkType.K8sGateway],
               JSON.stringify(k8sgateway),
               this.props.cluster
             )
@@ -394,7 +394,7 @@ export class ServiceWizard extends React.Component<ServiceWizardProps, ServiceWi
             promises.push(
               API.updateIstioConfigDetail(
                 this.props.namespace,
-                dicIstioTypeToGVK['DestinationRule'],
+                dicTypeToGVK[gvkType.DestinationRule],
                 dr.metadata.name,
                 JSON.stringify(dr),
                 this.props.cluster
@@ -406,7 +406,7 @@ export class ServiceWizard extends React.Component<ServiceWizardProps, ServiceWi
             promises.push(
               API.updateIstioConfigDetail(
                 this.props.namespace,
-                dicIstioTypeToGVK['VirtualService'],
+                dicTypeToGVK[gvkType.VirtualService],
                 vs.metadata.name,
                 JSON.stringify(vs),
                 this.props.cluster
@@ -418,7 +418,7 @@ export class ServiceWizard extends React.Component<ServiceWizardProps, ServiceWi
             promises.push(
               API.updateIstioConfigDetail(
                 this.props.namespace,
-                dicIstioTypeToGVK['K8sHTTPRoute'],
+                dicTypeToGVK[gvkType.K8sHTTPRoute],
                 k8shttproute.metadata.name,
                 JSON.stringify(k8shttproute),
                 this.props.cluster
@@ -430,7 +430,7 @@ export class ServiceWizard extends React.Component<ServiceWizardProps, ServiceWi
             promises.push(
               API.updateIstioConfigDetail(
                 this.props.namespace,
-                dicIstioTypeToGVK['K8sGRPCRoute'],
+                dicTypeToGVK[gvkType.K8sGRPCRoute],
                 k8sgrpcroute.metadata.name,
                 JSON.stringify(k8sgrpcroute),
                 this.props.cluster
@@ -447,7 +447,7 @@ export class ServiceWizard extends React.Component<ServiceWizardProps, ServiceWi
             promises.push(
               API.createIstioConfigDetail(
                 this.props.namespace,
-                dicIstioTypeToGVK['DestinationRule'],
+                dicTypeToGVK[gvkType.DestinationRule],
                 JSON.stringify(dr),
                 this.props.cluster
               )
@@ -458,7 +458,7 @@ export class ServiceWizard extends React.Component<ServiceWizardProps, ServiceWi
             promises.push(
               API.createIstioConfigDetail(
                 this.props.namespace,
-                dicIstioTypeToGVK['VirtualService'],
+                dicTypeToGVK[gvkType.VirtualService],
                 JSON.stringify(vs),
                 this.props.cluster
               )
@@ -469,7 +469,7 @@ export class ServiceWizard extends React.Component<ServiceWizardProps, ServiceWi
             promises.push(
               API.createIstioConfigDetail(
                 this.props.namespace,
-                dicIstioTypeToGVK['K8sHTTPRoute'],
+                dicTypeToGVK[gvkType.K8sHTTPRoute],
                 JSON.stringify(k8shttproute),
                 this.props.cluster
               )
@@ -480,7 +480,7 @@ export class ServiceWizard extends React.Component<ServiceWizardProps, ServiceWi
             promises.push(
               API.createIstioConfigDetail(
                 this.props.namespace,
-                dicIstioTypeToGVK['K8sGRPCRoute'],
+                dicTypeToGVK[gvkType.K8sGRPCRoute],
                 JSON.stringify(k8sgrpcroute),
                 this.props.cluster
               )
@@ -491,7 +491,7 @@ export class ServiceWizard extends React.Component<ServiceWizardProps, ServiceWi
             promises.push(
               API.createIstioConfigDetail(
                 this.props.namespace,
-                dicIstioTypeToGVK['PeerAuthentication'],
+                dicTypeToGVK[gvkType.PeerAuthentication],
                 JSON.stringify(pa),
                 this.props.cluster
               )
@@ -539,7 +539,7 @@ export class ServiceWizard extends React.Component<ServiceWizardProps, ServiceWi
         promises.push(
           API.createIstioConfigDetail(
             this.props.namespace,
-            dicIstioTypeToGVK['PeerAuthentication'],
+            dicTypeToGVK[gvkType.PeerAuthentication],
             JSON.stringify(pa),
             this.props.cluster
           )
@@ -548,7 +548,7 @@ export class ServiceWizard extends React.Component<ServiceWizardProps, ServiceWi
         promises.push(
           API.updateIstioConfigDetail(
             this.props.namespace,
-            dicIstioTypeToGVK['PeerAuthentication'],
+            dicTypeToGVK[gvkType.PeerAuthentication],
             dr.metadata.name,
             JSON.stringify(pa),
             this.props.cluster
@@ -559,7 +559,7 @@ export class ServiceWizard extends React.Component<ServiceWizardProps, ServiceWi
       promises.push(
         API.deleteIstioConfigDetail(
           this.props.namespace,
-          dicIstioTypeToGVK['PeerAuthentication'],
+          dicTypeToGVK[gvkType.PeerAuthentication],
           dr.metadata.name,
           this.props.cluster
         )
@@ -756,13 +756,17 @@ export class ServiceWizard extends React.Component<ServiceWizardProps, ServiceWi
   };
 
   onConfirmPreview = (items: ConfigPreviewItem[]): void => {
-    const dr = items.filter(it => getGVKTypeString(it.objectGVK) === getGVKTypeString('DestinationRule'))[0];
-    const gw = items.filter(it => getGVKTypeString(it.objectGVK) === getGVKTypeString('Gateway'))[0];
-    const k8sgateway = items.filter(it => getGVKTypeString(it.objectGVK) === getGVKTypeString('K8sGateway'))[0];
-    const pa = items.filter(it => getGVKTypeString(it.objectGVK) === getGVKTypeString('PeerAuthentication'))[0];
-    const vs = items.filter(it => getGVKTypeString(it.objectGVK) === getGVKTypeString('VirtualService'))[0];
-    const k8shttproute = items.filter(it => getGVKTypeString(it.objectGVK) === getGVKTypeString('K8sHTTPRoute'))[0];
-    const k8sgrpcroute = items.filter(it => getGVKTypeString(it.objectGVK) === getGVKTypeString('K8sGRPCRoute'))[0];
+    const dr = items.filter(it => getGVKTypeString(it.objectGVK) === getGVKTypeString(gvkType.DestinationRule))[0];
+    const gw = items.filter(it => getGVKTypeString(it.objectGVK) === getGVKTypeString(gvkType.Gateway))[0];
+    const k8sgateway = items.filter(it => getGVKTypeString(it.objectGVK) === getGVKTypeString(gvkType.K8sGateway))[0];
+    const pa = items.filter(it => getGVKTypeString(it.objectGVK) === getGVKTypeString(gvkType.PeerAuthentication))[0];
+    const vs = items.filter(it => getGVKTypeString(it.objectGVK) === getGVKTypeString(gvkType.VirtualService))[0];
+    const k8shttproute = items.filter(
+      it => getGVKTypeString(it.objectGVK) === getGVKTypeString(gvkType.K8sHTTPRoute)
+    )[0];
+    const k8sgrpcroute = items.filter(
+      it => getGVKTypeString(it.objectGVK) === getGVKTypeString(gvkType.K8sGRPCRoute)
+    )[0];
 
     const previews: WizardPreviews = {
       dr: dr ? (dr.items[0] as DestinationRule) : undefined,
@@ -783,19 +787,19 @@ export class ServiceWizard extends React.Component<ServiceWizardProps, ServiceWi
     if (this.state.previews) {
       if (this.state.previews.dr) {
         items.push({
-          objectGVK: dicIstioTypeToGVK['DestinationRule'],
+          objectGVK: dicTypeToGVK[gvkType.DestinationRule],
           items: [this.state.previews.dr],
           title: 'Destination Rule'
         });
       }
 
       if (this.state.previews.gw) {
-        items.push({ objectGVK: dicIstioTypeToGVK['Gateway'], items: [this.state.previews.gw], title: 'Gateway' });
+        items.push({ objectGVK: dicTypeToGVK[gvkType.Gateway], items: [this.state.previews.gw], title: 'Gateway' });
       }
 
       if (this.state.previews.k8sgateway) {
         items.push({
-          objectGVK: dicIstioTypeToGVK['K8sGateway'],
+          objectGVK: dicTypeToGVK[gvkType.K8sGateway],
           items: [this.state.previews.k8sgateway],
           title: 'K8s Gateway'
         });
@@ -803,7 +807,7 @@ export class ServiceWizard extends React.Component<ServiceWizardProps, ServiceWi
 
       if (this.state.previews.k8shttproute) {
         items.push({
-          objectGVK: dicIstioTypeToGVK['K8sHTTPRoute'],
+          objectGVK: dicTypeToGVK[gvkType.K8sHTTPRoute],
           items: [this.state.previews.k8shttproute],
           title: 'K8s HTTPRoute'
         });
@@ -811,7 +815,7 @@ export class ServiceWizard extends React.Component<ServiceWizardProps, ServiceWi
 
       if (this.state.previews.k8sgrpcroute) {
         items.push({
-          objectGVK: dicIstioTypeToGVK['K8sGRPCRoute'],
+          objectGVK: dicTypeToGVK[gvkType.K8sGRPCRoute],
           items: [this.state.previews.k8sgrpcroute],
           title: 'K8s GRPCRoute'
         });
@@ -819,7 +823,7 @@ export class ServiceWizard extends React.Component<ServiceWizardProps, ServiceWi
 
       if (this.state.previews.pa) {
         items.push({
-          objectGVK: dicIstioTypeToGVK['PeerAuthentication'],
+          objectGVK: dicTypeToGVK[gvkType.PeerAuthentication],
           items: [this.state.previews.pa],
           title: 'Peer Authentication'
         });
@@ -827,7 +831,7 @@ export class ServiceWizard extends React.Component<ServiceWizardProps, ServiceWi
 
       if (this.state.previews.vs) {
         items.push({
-          objectGVK: dicIstioTypeToGVK['VirtualService'],
+          objectGVK: dicTypeToGVK[gvkType.VirtualService],
           items: [this.state.previews.vs],
           title: 'VirtualService'
         });
diff --git a/frontend/src/components/IstioWizards/WizardActions.ts b/frontend/src/components/IstioWizards/WizardActions.ts
index e99235fa5..bbd623147 100644
--- a/frontend/src/components/IstioWizards/WizardActions.ts
+++ b/frontend/src/components/IstioWizards/WizardActions.ts
@@ -11,6 +11,7 @@ import {
   ConnectionPoolSettings,
   DestinationRule,
   Gateway,
+  GroupVersionKind,
   HTTPMatchRequest,
   HTTPRoute,
   HTTPRouteDestination,
@@ -68,6 +69,7 @@ import { ADD, SET, REQ_MOD, RESP_MOD, REQ_RED, REQ_MIR } from './K8sRequestRouti
 import { ANYTHING, PRESENCE } from './RequestRouting/MatchBuilder';
 import { t } from 'utils/I18nUtils';
 import { defaultGatewayLabel, defaultGatewayLabelValue } from 'config/Constants';
+import { dicTypeToGVK, gvkType } from '../../types/IstioConfigList';
 
 export const WIZARD_TRAFFIC_SHIFTING = 'traffic_shifting';
 export const WIZARD_TCP_TRAFFIC_SHIFTING = 'tcp_traffic_shifting';
@@ -2366,7 +2368,7 @@ export const buildNamespaceInjectionPatch = (enable: boolean, remove: boolean, r
   return JSON.stringify(patch);
 };
 
-export const buildWorkloadInjectionPatch = (workloadType: string, enable: boolean, remove: boolean): string => {
+export const buildWorkloadInjectionPatch = (gvk: GroupVersionKind, enable: boolean, remove: boolean): string => {
   const patch = {};
 
   // environments prefer to use the pod label over the annotation
@@ -2375,7 +2377,7 @@ export const buildWorkloadInjectionPatch = (workloadType: string, enable: boolea
   labels[serverConfig.istioAnnotations.istioInjectionAnnotation] = remove ? null : enable ? 'true' : 'false';
   const annotations = {};
   annotations[serverConfig.istioAnnotations.istioInjectionAnnotation] = null;
-  if (workloadType === 'Pod') {
+  if (gvk.Kind === dicTypeToGVK[gvkType.Pod].Kind) {
     patch['labels'] = labels;
     patch['annotations'] = annotations;
   } else {
diff --git a/frontend/src/components/IstioWizards/WorkloadWizardActionsDropdownGroup.tsx b/frontend/src/components/IstioWizards/WorkloadWizardActionsDropdownGroup.tsx
index ae80ea7d5..c2119c61c 100644
--- a/frontend/src/components/IstioWizards/WorkloadWizardActionsDropdownGroup.tsx
+++ b/frontend/src/components/IstioWizards/WorkloadWizardActionsDropdownGroup.tsx
@@ -15,6 +15,8 @@ import { renderDisabledDropdownOption } from 'utils/DropdownUtils';
 import { MessageType } from 'types/MessageCenter';
 import { groupMenuStyle } from 'styles/DropdownStyles';
 import { t } from 'utils/I18nUtils';
+import { getGVKTypeString } from '../../utils/IstioConfigUtils';
+import { gvkType } from '../../types/IstioConfigList';
 
 type Props = {
   actionsLabel: boolean;
@@ -34,11 +36,11 @@ export const WorkloadWizardActionsDropdownGroup: React.FunctionComponent<Props>
       case WIZARD_REMOVE_AUTO_INJECTION:
         const remove = key === WIZARD_REMOVE_AUTO_INJECTION;
         const enable = key === WIZARD_ENABLE_AUTO_INJECTION;
-        const jsonInjectionPatch = buildWorkloadInjectionPatch(props.workload.type, enable, remove);
+        const jsonInjectionPatch = buildWorkloadInjectionPatch(props.workload.gvk, enable, remove);
         API.updateWorkload(
           props.namespace,
           props.workload.name,
-          props.workload.type,
+          props.workload.gvk,
           jsonInjectionPatch,
           undefined,
           props.workload.cluster
@@ -139,7 +141,7 @@ export const WorkloadWizardActionsDropdownGroup: React.FunctionComponent<Props>
   }
 
   // Annotations
-  if (props.annotations && props.workload.type === 'Deployment') {
+  if (props.annotations && getGVKTypeString(props.workload.gvk) === getGVKTypeString(gvkType.Deployment)) {
     const annotationsAction = (
       <DropdownItem
         data-test={WIZARD_EDIT_ANNOTATIONS}
diff --git a/frontend/src/components/IstioWizards/WorkloadWizardDropdown.tsx b/frontend/src/components/IstioWizards/WorkloadWizardDropdown.tsx
index fc8c69b4d..76f29d59c 100644
--- a/frontend/src/components/IstioWizards/WorkloadWizardDropdown.tsx
+++ b/frontend/src/components/IstioWizards/WorkloadWizardDropdown.tsx
@@ -17,6 +17,8 @@ import { WizardLabels } from './WizardLabels';
 import { renderDisabledDropdownOption } from 'utils/DropdownUtils';
 import { WorkloadWizardActionsDropdownGroup } from './WorkloadWizardActionsDropdownGroup';
 import { t } from 'utils/I18nUtils';
+import { getGVKTypeString, isGVKSupported } from '../../utils/IstioConfigUtils';
+import { gvkType } from '../../types/IstioConfigList';
 
 interface Props {
   namespace: string;
@@ -46,7 +48,7 @@ export const WorkloadWizardDropdown: React.FC<Props> = (props: Props) => {
     API.updateWorkload(
       props.namespace,
       props.workload.name,
-      props.workload.type,
+      props.workload.gvk,
       jsonInjectionPatch,
       'json',
       props.workload.cluster
@@ -92,7 +94,9 @@ export const WorkloadWizardDropdown: React.FC<Props> = (props: Props) => {
     //  istio actions
     (serverConfig.kialiFeatureFlags.istioInjectionAction && !props.workload.isAmbient) ||
     // annotations
-    props.workload.type === 'Deployment';
+    getGVKTypeString(props.workload.gvk) === getGVKTypeString(gvkType.Deployment);
+
+  const supportedWorkload = isGVKSupported(props.workload.gvk);
 
   const dropdown = (
     <Dropdown
@@ -105,7 +109,7 @@ export const WorkloadWizardDropdown: React.FC<Props> = (props: Props) => {
           onClick={() => onActionsToggle(!isActionsOpen)}
           data-test="workload-actions-toggle"
           isExpanded={isActionsOpen}
-          isDisabled={!validActions}
+          isDisabled={!validActions || !supportedWorkload}
         >
           {t('Actions')}
         </MenuToggle>
@@ -144,6 +148,13 @@ export const WorkloadWizardDropdown: React.FC<Props> = (props: Props) => {
             t('User does not have permission on this Workload'),
             dropdown
           )
+        : !supportedWorkload
+        ? renderDisabledDropdownOption(
+            'tooltip_wizard_actions',
+            TooltipPosition.top,
+            t('This type of workload is read-only'),
+            dropdown
+          )
         : dropdown}
     </>
   );
diff --git a/frontend/src/components/VirtualList/Config.ts b/frontend/src/components/VirtualList/Config.ts
index da23244d6..cc20e678b 100644
--- a/frontend/src/components/VirtualList/Config.ts
+++ b/frontend/src/components/VirtualList/Config.ts
@@ -4,14 +4,14 @@ import { AppWorkload } from 'types/App';
 import { isWaypoint } from 'helpers/LabelFilterHelper';
 import { WorkloadListItem, Workload } from '../../types/Workload';
 import { ServiceListItem } from '../../types/ServiceList';
-import { dicIstioTypeToGVK, IstioConfigItem } from '../../types/IstioConfigList';
+import { dicTypeToGVK, IstioConfigItem } from '../../types/IstioConfigList';
 import * as Renderers from './Renderers';
 import { Health } from '../../types/Health';
 import { isIstioNamespace } from 'config/ServerConfig';
 import { NamespaceInfo } from '../../types/NamespaceInfo';
 import { StatefulFiltersRef } from '../Filters/StatefulFilters';
 import { PFBadges, PFBadgeType } from '../../components/Pf/PfBadges';
-import { getGVKTypeString } from '../../utils/IstioConfigUtils';
+import { getGVKTypeString, kindToStringIncludeK8s } from '../../utils/IstioConfigUtils';
 
 export type SortResource = AppListItem | WorkloadListItem | ServiceListItem;
 export type TResource = SortResource | IstioConfigItem;
@@ -201,8 +201,8 @@ const istioType: ResourceType<IstioConfigItem> = {
 
 export const GVKToBadge: { [gvk: string]: PFBadgeType } = {};
 
-Object.keys(dicIstioTypeToGVK).forEach(key => {
-  GVKToBadge[getGVKTypeString(key)] = PFBadges[key];
+Object.values(dicTypeToGVK).forEach(value => {
+  GVKToBadge[getGVKTypeString(value)] = PFBadges[kindToStringIncludeK8s(value.Group, value.Kind)];
 });
 
 export type Resource = {
diff --git a/frontend/src/components/VirtualList/Renderers.tsx b/frontend/src/components/VirtualList/Renderers.tsx
index e7c01a545..b76819be3 100644
--- a/frontend/src/components/VirtualList/Renderers.tsx
+++ b/frontend/src/components/VirtualList/Renderers.tsx
@@ -443,7 +443,7 @@ export const workloadType: Renderer<WorkloadListItem> = (item: WorkloadListItem)
       key={`VirtuaItem_WorkloadType_${item.namespace}_${item.name}`}
       style={{ verticalAlign: 'middle' }}
     >
-      {item.type}
+      {item.gvk.Kind}
     </Td>
   );
 };
diff --git a/frontend/src/components/VirtualList/VirtualItem.tsx b/frontend/src/components/VirtualList/VirtualItem.tsx
index e4d233ecc..72d307c42 100644
--- a/frontend/src/components/VirtualList/VirtualItem.tsx
+++ b/frontend/src/components/VirtualList/VirtualItem.tsx
@@ -68,6 +68,8 @@ export class VirtualItem extends React.Component<VirtualItemProps, VirtualItemSt
         ? `_${item.type}`
         : 'kind' in item && 'apiVersion' in item
         ? `_${kindToStringIncludeK8s(item.apiVersion, item.kind)}`
+        : 'gvk' in item
+        ? `_${item.gvk.Kind}`
         : '';
     // End result looks like: VirtualItem_Clusterwest_Nsbookinfo_networking.istio.io.v1.Gateway_bookinfo-gateway
 
diff --git a/frontend/src/hooks/services.ts b/frontend/src/hooks/services.ts
index 4c2a17b5b..7ca9acaa4 100644
--- a/frontend/src/hooks/services.ts
+++ b/frontend/src/hooks/services.ts
@@ -8,6 +8,7 @@ import { DecoratedGraphNodeData, NodeType } from '../types/Graph';
 import * as AlertUtils from '../utils/AlertUtils';
 import { ApiError } from 'types/Api';
 import { getGVKTypeString } from '../utils/IstioConfigUtils';
+import { gvkType } from '../types/IstioConfigList';
 
 type ServiceDetailHookInfo = readonly [
   ServiceDetailsInfo | null,
@@ -38,10 +39,10 @@ const useServiceDetail = (
 
     setIsLoading(true); // Mark as loading
     let getDetailPromise = API.getServiceDetail(namespace, serviceName, false, cluster, duration);
-    let getGwPromise = API.getAllIstioConfigs([getGVKTypeString('Gateway')], false, '', '', cluster);
+    let getGwPromise = API.getAllIstioConfigs([getGVKTypeString(gvkType.Gateway)], false, '', '', cluster);
     let getPeerAuthsPromise = API.getIstioConfig(
       namespace,
-      [getGVKTypeString('PeerAuthentication')],
+      [getGVKTypeString(gvkType.PeerAuthentication)],
       false,
       '',
       '',
@@ -53,10 +54,12 @@ const useServiceDetail = (
       .then(results => {
         setServiceDetails(results[0]);
         setGateways(
-          getGatewaysAsList(filterAutogeneratedGateways(results[1].data.resources[getGVKTypeString('Gateway')])).sort()
+          getGatewaysAsList(
+            filterAutogeneratedGateways(results[1].data.resources[getGVKTypeString(gvkType.Gateway)])
+          ).sort()
         );
 
-        setPeerAuthentications(results[2].data.resources[getGVKTypeString('PeerAuthentication')]);
+        setPeerAuthentications(results[2].data.resources[getGVKTypeString(gvkType.PeerAuthentication)]);
         setFetchError(null);
         setIsLoading(false);
       })
diff --git a/frontend/src/pages/Graph/SummaryLink.tsx b/frontend/src/pages/Graph/SummaryLink.tsx
index d14a6cfe2..eefbf3e1b 100644
--- a/frontend/src/pages/Graph/SummaryLink.tsx
+++ b/frontend/src/pages/Graph/SummaryLink.tsx
@@ -17,7 +17,7 @@ import { KialiPageLink } from 'components/Link/KialiPageLink';
 import { kialiStyle } from 'styles/StyleUtils';
 import { t } from 'utils/I18nUtils';
 import { ExternalLinkAltIcon } from '@patternfly/react-icons';
-import { dicIstioTypeToGVK } from '../../types/IstioConfigList';
+import { dicTypeToGVK, gvkType } from '../../types/IstioConfigList';
 
 interface LinkInfo {
   displayName: string;
@@ -186,7 +186,7 @@ export const getLink = (
         break;
       case NodeType.SERVICE:
         if (nodeData.isServiceEntry) {
-          const seGVK = dicIstioTypeToGVK['ServiceEntry'];
+          const seGVK = dicTypeToGVK[gvkType.ServiceEntry];
           link = `/namespaces/${encodeURIComponent(nodeData.isServiceEntry.namespace)}/istio/${seGVK.Group}/${
             seGVK.Version
           }/${seGVK.Kind}/${encodeURIComponent(service!)}`;
diff --git a/frontend/src/pages/Graph/SummaryPanelNode.tsx b/frontend/src/pages/Graph/SummaryPanelNode.tsx
index 530b9bf30..3f9d936ad 100644
--- a/frontend/src/pages/Graph/SummaryPanelNode.tsx
+++ b/frontend/src/pages/Graph/SummaryPanelNode.tsx
@@ -40,7 +40,7 @@ import { groupMenuStyle, kebabToggleStyle } from 'styles/DropdownStyles';
 import { isMultiCluster, serverConfig } from '../../config';
 import { panelBodyStyle, panelHeadingStyle, panelStyle } from './SummaryPanelStyle';
 import { renderWaypoint } from '../../components/DetailDescription/DetailDescription';
-import { dicIstioTypeToGVK } from '../../types/IstioConfigList';
+import { dicTypeToGVK, gvkType } from '../../types/IstioConfigList';
 
 type SummaryPanelNodeState = {
   isActionOpen: boolean;
@@ -256,7 +256,7 @@ export class SummaryPanelNodeComponent extends React.Component<SummaryPanelNodeC
     if (!nodeData.hasWorkloadEntry) {
       return <div>{renderBadgedLink(nodeData, NodeType.WORKLOAD)}</div>;
     }
-    const weGVK = dicIstioTypeToGVK['WorkloadEntry'];
+    const weGVK = dicTypeToGVK[gvkType.WorkloadEntry];
 
     const workloadEntryLinks = nodeData.hasWorkloadEntry.map(we => (
       <div>
diff --git a/frontend/src/pages/GraphPF/components/stylesComponentFactory.tsx b/frontend/src/pages/GraphPF/components/stylesComponentFactory.tsx
index 744ddf84b..92631a2b6 100644
--- a/frontend/src/pages/GraphPF/components/stylesComponentFactory.tsx
+++ b/frontend/src/pages/GraphPF/components/stylesComponentFactory.tsx
@@ -35,6 +35,7 @@ import { ServiceDetailsInfo } from 'types/ServiceInfo';
 import { kialiStyle } from 'styles/StyleUtils';
 import { DropdownGroup, DropdownItem } from '@patternfly/react-core';
 import { getGVKTypeString } from '../../../utils/IstioConfigUtils';
+import { gvkType } from '../../../types/IstioConfigList';
 
 type ContextMenuOptionPF = ContextMenuOption & {
   altClickHandler?: (node: GraphElement, kiosk: string) => void;
@@ -121,11 +122,18 @@ const nodeContextMenu = (node: GraphElement, kiosk: string): Promise<React.React
   );
   const getGwPromise = promises.register(
     'getGwPromise',
-    API.getAllIstioConfigs([getGVKTypeString('Gateway')], false, '', '', nodeData.cluster)
+    API.getAllIstioConfigs([getGVKTypeString(gvkType.Gateway)], false, '', '', nodeData.cluster)
   );
   const getPeerAuthsPromise = promises.register(
     'getPeerAuthsPromise',
-    API.getIstioConfig(nodeData.namespace, [getGVKTypeString('PeerAuthentication')], false, '', '', nodeData.cluster)
+    API.getIstioConfig(
+      nodeData.namespace,
+      [getGVKTypeString(gvkType.PeerAuthentication)],
+      false,
+      '',
+      '',
+      nodeData.cluster
+    )
   );
 
   return new Promise<React.ReactElement[]>((resolve, reject) => {
@@ -133,9 +141,9 @@ const nodeContextMenu = (node: GraphElement, kiosk: string): Promise<React.React
       .then(results => {
         const serviceDetails = results[0];
         const gateways = getGatewaysAsList(
-          filterAutogeneratedGateways(results[1].data.resources[getGVKTypeString('Gateway')])
+          filterAutogeneratedGateways(results[1].data.resources[getGVKTypeString(gvkType.Gateway)])
         ).sort();
-        const peerAuthentications = results[2].data.resources[getGVKTypeString('PeerAuthentication')];
+        const peerAuthentications = results[2].data.resources[getGVKTypeString(gvkType.PeerAuthentication)];
 
         items.push(
           <ServiceWizardActionsDropdownGroup
diff --git a/frontend/src/pages/IstioConfigList/IstioConfigListPage.tsx b/frontend/src/pages/IstioConfigList/IstioConfigListPage.tsx
index a1e1f3036..2d0cb20b6 100644
--- a/frontend/src/pages/IstioConfigList/IstioConfigListPage.tsx
+++ b/frontend/src/pages/IstioConfigList/IstioConfigListPage.tsx
@@ -7,6 +7,7 @@ import {
   filterByConfigValidation,
   filterByName,
   filterByNamespaces,
+  gvkType,
   IstioConfigItem,
   toIstioItems
 } from '../../types/IstioConfigList';
@@ -106,7 +107,7 @@ class IstioConfigListPageComponent extends FilterComponent.Component<
     const namespacesSelected = this.props.activeNamespaces!.map(item => item.name);
 
     const istioTypeFilters = getFilterSelectedValues(IstioConfigListFilters.istioTypeFilter, activeFilters).map(value =>
-      getGVKTypeString(value)
+      getGVKTypeString(gvkType[value])
     );
 
     const istioNameFilters = getFilterSelectedValues(IstioConfigListFilters.istioNameFilter, activeFilters);
diff --git a/frontend/src/pages/IstioConfigNew/IstioConfigNewPage.tsx b/frontend/src/pages/IstioConfigNew/IstioConfigNewPage.tsx
index 7c925b8c9..2665a6a88 100644
--- a/frontend/src/pages/IstioConfigNew/IstioConfigNewPage.tsx
+++ b/frontend/src/pages/IstioConfigNew/IstioConfigNewPage.tsx
@@ -72,7 +72,7 @@ import { NamespaceDropdown } from '../../components/Dropdown/NamespaceDropdown';
 import { Labels } from '../../components/Label/Labels';
 import { WizardLabels } from '../../components/IstioWizards/WizardLabels';
 import { isParentKiosk, kioskContextMenuAction } from 'components/Kiosk/KioskActions';
-import { dicIstioTypeToGVK } from '../../types/IstioConfigList';
+import { dicTypeToGVK, gvkType } from '../../types/IstioConfigList';
 import { getGVKTypeString } from '../../utils/IstioConfigUtils';
 import { GroupVersionKind } from '../../types/IstioObjects';
 
@@ -126,14 +126,14 @@ const editStyle = kialiStyle({
 
 // Used in the Istio Config list Actions
 export const NEW_ISTIO_RESOURCE = [
-  { value: dicIstioTypeToGVK['AuthorizationPolicy'], disabled: false },
-  { value: dicIstioTypeToGVK['Gateway'], disabled: false },
-  { value: dicIstioTypeToGVK['K8sGateway'], disabled: false },
-  { value: dicIstioTypeToGVK['K8sReferenceGrant'], disabled: false },
-  { value: dicIstioTypeToGVK['PeerAuthentication'], disabled: false },
-  { value: dicIstioTypeToGVK['RequestAuthentication'], disabled: false },
-  { value: dicIstioTypeToGVK['ServiceEntry'], disabled: false },
-  { value: dicIstioTypeToGVK['Sidecar'], disabled: false }
+  { value: dicTypeToGVK[gvkType.AuthorizationPolicy], disabled: false },
+  { value: dicTypeToGVK[gvkType.Gateway], disabled: false },
+  { value: dicTypeToGVK[gvkType.K8sGateway], disabled: false },
+  { value: dicTypeToGVK[gvkType.K8sReferenceGrant], disabled: false },
+  { value: dicTypeToGVK[gvkType.PeerAuthentication], disabled: false },
+  { value: dicTypeToGVK[gvkType.RequestAuthentication], disabled: false },
+  { value: dicTypeToGVK[gvkType.ServiceEntry], disabled: false },
+  { value: dicTypeToGVK[gvkType.Sidecar], disabled: false }
 ];
 
 const initState = (): State => ({
@@ -336,7 +336,7 @@ class IstioConfigNewPageComponent extends React.Component<Props, State> {
     const items: ConfigPreviewItem[] = [];
     this.props.activeNamespaces.forEach(ns => {
       switch (getGVKTypeString(this.props.objectGVK)) {
-        case getGVKTypeString('AuthorizationPolicy'):
+        case getGVKTypeString(gvkType.AuthorizationPolicy):
           items.push({
             title: 'Authorization Policy',
             objectGVK: this.props.objectGVK,
@@ -351,7 +351,7 @@ class IstioConfigNewPageComponent extends React.Component<Props, State> {
             ]
           });
           break;
-        case getGVKTypeString('Gateway'):
+        case getGVKTypeString(gvkType.Gateway):
           items.push({
             title: 'Gateway',
             objectGVK: this.props.objectGVK,
@@ -360,7 +360,7 @@ class IstioConfigNewPageComponent extends React.Component<Props, State> {
             ]
           });
           break;
-        case getGVKTypeString('K8sGateway'):
+        case getGVKTypeString(gvkType.K8sGateway):
           items.push({
             title: 'K8s Gateway',
             objectGVK: this.props.objectGVK,
@@ -375,7 +375,7 @@ class IstioConfigNewPageComponent extends React.Component<Props, State> {
             ]
           });
           break;
-        case getGVKTypeString('K8sReferenceGrant'):
+        case getGVKTypeString(gvkType.K8sReferenceGrant):
           items.push({
             title: 'K8s Reference Grant',
             objectGVK: this.props.objectGVK,
@@ -390,7 +390,7 @@ class IstioConfigNewPageComponent extends React.Component<Props, State> {
             ]
           });
           break;
-        case getGVKTypeString('PeerAuthentication'):
+        case getGVKTypeString(gvkType.PeerAuthentication):
           items.push({
             title: 'Peer Authentication',
             objectGVK: this.props.objectGVK,
@@ -405,7 +405,7 @@ class IstioConfigNewPageComponent extends React.Component<Props, State> {
             ]
           });
           break;
-        case getGVKTypeString('RequestAuthentication'):
+        case getGVKTypeString(gvkType.RequestAuthentication):
           items.push({
             title: 'Request Authentication',
             objectGVK: this.props.objectGVK,
@@ -420,7 +420,7 @@ class IstioConfigNewPageComponent extends React.Component<Props, State> {
             ]
           });
           break;
-        case getGVKTypeString('ServiceEntry'):
+        case getGVKTypeString(gvkType.ServiceEntry):
           items.push({
             title: 'Service Entry',
             objectGVK: this.props.objectGVK,
@@ -435,7 +435,7 @@ class IstioConfigNewPageComponent extends React.Component<Props, State> {
             ]
           });
           break;
-        case getGVKTypeString('Sidecar'):
+        case getGVKTypeString(gvkType.Sidecar):
           items.push({
             title: 'Sidecar',
             objectGVK: this.props.objectGVK,
@@ -465,21 +465,21 @@ class IstioConfigNewPageComponent extends React.Component<Props, State> {
 
   isIstioFormValid = (): boolean => {
     switch (getGVKTypeString(this.props.objectGVK)) {
-      case getGVKTypeString('AuthorizationPolicy'):
+      case getGVKTypeString(gvkType.AuthorizationPolicy):
         return isAuthorizationPolicyStateValid(this.state.authorizationPolicy);
-      case getGVKTypeString('Gateway'):
+      case getGVKTypeString(gvkType.Gateway):
         return isGatewayStateValid(this.state.gateway);
-      case getGVKTypeString('K8sGateway'):
+      case getGVKTypeString(gvkType.K8sGateway):
         return isK8sGatewayStateValid(this.state.k8sGateway);
-      case getGVKTypeString('K8sReferenceGrant'):
+      case getGVKTypeString(gvkType.K8sReferenceGrant):
         return isK8sReferenceGrantStateValid(this.state.k8sReferenceGrant);
-      case getGVKTypeString('PeerAuthentication'):
+      case getGVKTypeString(gvkType.PeerAuthentication):
         return isPeerAuthenticationStateValid(this.state.peerAuthentication);
-      case getGVKTypeString('RequestAuthentication'):
+      case getGVKTypeString(gvkType.RequestAuthentication):
         return isRequestAuthenticationStateValid(this.state.requestAuthentication);
-      case getGVKTypeString('ServiceEntry'):
+      case getGVKTypeString(gvkType.ServiceEntry):
         return isServiceEntryValid(this.state.serviceEntry);
-      case getGVKTypeString('Sidecar'):
+      case getGVKTypeString(gvkType.Sidecar):
         return isSidecarStateValid(this.state.sidecar);
       default:
         return false;
@@ -625,47 +625,47 @@ class IstioConfigNewPageComponent extends React.Component<Props, State> {
               )}
             </FormGroup>
 
-            {getGVKTypeString(this.props.objectGVK) === getGVKTypeString('AuthorizationPolicy') && (
+            {getGVKTypeString(this.props.objectGVK) === getGVKTypeString(gvkType.AuthorizationPolicy) && (
               <AuthorizationPolicyForm
                 authorizationPolicy={this.state.authorizationPolicy}
                 onChange={this.onChangeAuthorizationPolicy}
               />
             )}
 
-            {getGVKTypeString(this.props.objectGVK) === getGVKTypeString('Gateway') && (
+            {getGVKTypeString(this.props.objectGVK) === getGVKTypeString(gvkType.Gateway) && (
               <GatewayForm gateway={this.state.gateway} onChange={this.onChangeGateway} />
             )}
 
-            {getGVKTypeString(this.props.objectGVK) === getGVKTypeString('K8sGateway') && (
+            {getGVKTypeString(this.props.objectGVK) === getGVKTypeString(gvkType.K8sGateway) && (
               <K8sGatewayForm k8sGateway={this.state.k8sGateway} onChange={this.onChangeK8sGateway} />
             )}
 
-            {getGVKTypeString(this.props.objectGVK) === getGVKTypeString('K8sReferenceGrant') && (
+            {getGVKTypeString(this.props.objectGVK) === getGVKTypeString(gvkType.K8sReferenceGrant) && (
               <K8sReferenceGrantForm
                 k8sReferenceGrant={this.state.k8sReferenceGrant}
                 onChange={this.onChangeK8sReferenceGrant}
               />
             )}
 
-            {getGVKTypeString(this.props.objectGVK) === getGVKTypeString('PeerAuthentication') && (
+            {getGVKTypeString(this.props.objectGVK) === getGVKTypeString(gvkType.PeerAuthentication) && (
               <PeerAuthenticationForm
                 peerAuthentication={this.state.peerAuthentication}
                 onChange={this.onChangePeerAuthentication}
               />
             )}
 
-            {getGVKTypeString(this.props.objectGVK) === getGVKTypeString('RequestAuthentication') && (
+            {getGVKTypeString(this.props.objectGVK) === getGVKTypeString(gvkType.RequestAuthentication) && (
               <RequestAuthenticationForm
                 requestAuthentication={this.state.requestAuthentication}
                 onChange={this.onChangeRequestAuthentication}
               />
             )}
 
-            {getGVKTypeString(this.props.objectGVK) === getGVKTypeString('ServiceEntry') && (
+            {getGVKTypeString(this.props.objectGVK) === getGVKTypeString(gvkType.ServiceEntry) && (
               <ServiceEntryForm serviceEntry={this.state.serviceEntry} onChange={this.onChangeServiceEntry} />
             )}
 
-            {getGVKTypeString(this.props.objectGVK) === getGVKTypeString('Sidecar') && (
+            {getGVKTypeString(this.props.objectGVK) === getGVKTypeString(gvkType.Sidecar) && (
               <SidecarForm sidecar={this.state.sidecar} onChange={this.onChangeSidecar} />
             )}
 
diff --git a/frontend/src/pages/IstioConfigNew/K8sReferenceGrantForm.tsx b/frontend/src/pages/IstioConfigNew/K8sReferenceGrantForm.tsx
index 312c7bae5..39ce521b2 100644
--- a/frontend/src/pages/IstioConfigNew/K8sReferenceGrantForm.tsx
+++ b/frontend/src/pages/IstioConfigNew/K8sReferenceGrantForm.tsx
@@ -7,14 +7,14 @@ import { namespaceItemsSelector } from '../../store/Selectors';
 import { KialiDispatch } from '../../types/Redux';
 import { NamespaceThunkActions } from '../../actions/NamespaceThunkActions';
 import { connect } from 'react-redux';
-import { dicIstioTypeToGVK } from '../../types/IstioConfigList';
+import { dicTypeToGVK, gvkType } from '../../types/IstioConfigList';
 
 export const FROM_KINDS = [
-  dicIstioTypeToGVK['K8sHTTPRoute'],
-  dicIstioTypeToGVK['K8sGateway'],
-  dicIstioTypeToGVK['K8sGRPCRoute'],
-  dicIstioTypeToGVK['K8sTCPRoute'],
-  dicIstioTypeToGVK['K8sTLSRoute']
+  dicTypeToGVK[gvkType.K8sHTTPRoute],
+  dicTypeToGVK[gvkType.K8sGateway],
+  dicTypeToGVK[gvkType.K8sGRPCRoute],
+  dicTypeToGVK[gvkType.K8sTCPRoute],
+  dicTypeToGVK[gvkType.K8sTLSRoute]
 ];
 
 export const TO_KINDS = {
@@ -70,7 +70,7 @@ export class K8sReferenceGrantFormComponent extends React.Component<Props, K8sRe
   onChangeReferenceGrantFromKind = (_event: React.FormEvent, value: string): void => {
     this.setState(
       {
-        from: [{ group: dicIstioTypeToGVK[`K8s${value}`].Group, kind: value, namespace: this.state.from[0].namespace }]
+        from: [{ group: dicTypeToGVK[`K8s${value}`].Group, kind: value, namespace: this.state.from[0].namespace }]
       },
       () => this.props.onChange(this.state)
     );
diff --git a/frontend/src/pages/Overview/OverviewPage.tsx b/frontend/src/pages/Overview/OverviewPage.tsx
index cda0b1cb6..782222c99 100644
--- a/frontend/src/pages/Overview/OverviewPage.tsx
+++ b/frontend/src/pages/Overview/OverviewPage.tsx
@@ -73,7 +73,7 @@ import { ControlPlaneVersionBadge } from './ControlPlaneVersionBadge';
 import { AmbientBadge } from '../../components/Ambient/AmbientBadge';
 import { PFBadge, PFBadges } from 'components/Pf/PfBadges';
 import { ApiError } from 'types/Api';
-import { IstioConfigList } from 'types/IstioConfigList';
+import { gvkType, IstioConfigList } from 'types/IstioConfigList';
 import { t } from 'utils/I18nUtils';
 import { getGVKTypeString } from '../../utils/IstioConfigUtils';
 
@@ -880,7 +880,7 @@ export class OverviewPageComponent extends React.Component<OverviewProps, State>
         });
       }
 
-      const aps = nsInfo.istioConfig?.resources[getGVKTypeString('AuthorizationPolicy')] ?? [];
+      const aps = nsInfo.istioConfig?.resources[getGVKTypeString(gvkType.AuthorizationPolicy)] ?? [];
 
       const addAuthorizationAction = {
         isGroup: false,
diff --git a/frontend/src/pages/Overview/OverviewTrafficPolicies.tsx b/frontend/src/pages/Overview/OverviewTrafficPolicies.tsx
index 4dfea491a..9728f000e 100644
--- a/frontend/src/pages/Overview/OverviewTrafficPolicies.tsx
+++ b/frontend/src/pages/Overview/OverviewTrafficPolicies.tsx
@@ -15,7 +15,7 @@ import {
   buildNamespaceInjectionPatch,
   buildGraphSidecars
 } from 'components/IstioWizards/WizardActions';
-import { dicIstioTypeToGVK } from '../../types/IstioConfigList';
+import { dicTypeToGVK, gvkType } from '../../types/IstioConfigList';
 import { getGVKTypeString } from '../../utils/IstioConfigUtils';
 
 type OverviewTrafficPoliciesProps = {
@@ -73,8 +73,8 @@ export class OverviewTrafficPolicies extends React.Component<OverviewTrafficPoli
             this.fetchPermission();
           } else if (this.props.opTarget === 'update') {
             const authorizationPolicies =
-              this.props.nsInfo?.istioConfig?.resources[getGVKTypeString('AuthorizationPolicy')] ?? [];
-            const sidecars = this.props.nsInfo?.istioConfig?.resources[getGVKTypeString('Sidecar')] ?? [];
+              this.props.nsInfo?.istioConfig?.resources[getGVKTypeString(gvkType.AuthorizationPolicy)] ?? [];
+            const sidecars = this.props.nsInfo?.istioConfig?.resources[getGVKTypeString(gvkType.Sidecar)] ?? [];
             const remove = ['uid', 'resourceVersion', 'generation', 'creationTimestamp', 'managedFields'];
             sidecars.map(sdc => remove.map(key => delete sdc.metadata[key]));
             authorizationPolicies.map(ap => remove.map(key => delete ap.metadata[key]));
@@ -83,8 +83,8 @@ export class OverviewTrafficPolicies extends React.Component<OverviewTrafficPoli
             const nsInfo = this.props.nsInfo.istioConfig;
             this.setState(
               {
-                authorizationPolicies: nsInfo?.resources[getGVKTypeString('AuthorizationPolicy')] ?? [],
-                sidecars: nsInfo?.resources[getGVKTypeString('Sidecar')] ?? []
+                authorizationPolicies: nsInfo?.resources[getGVKTypeString(gvkType.AuthorizationPolicy)] ?? [],
+                sidecars: nsInfo?.resources[getGVKTypeString(gvkType.Sidecar)] ?? []
               },
               () => this.fetchPermission(true)
             );
@@ -101,7 +101,7 @@ export class OverviewTrafficPolicies extends React.Component<OverviewTrafficPoli
     this.promises
       .register('namespacepermissions', API.getIstioPermissions([this.props.nsTarget], this.props.nsInfo.cluster))
       .then(result => {
-        const permission = result.data[this.props.nsTarget][getGVKTypeString('AuthorizationPolicy')];
+        const permission = result.data[this.props.nsTarget][getGVKTypeString(gvkType.AuthorizationPolicy)];
         const disableOp = !(permission.create && permission.update && permission.delete);
         this.setState({
           confirmationModal,
@@ -183,10 +183,10 @@ export class OverviewTrafficPolicies extends React.Component<OverviewTrafficPoli
           'trafficPoliciesDelete',
           apsP
             .map(ap =>
-              API.deleteIstioConfigDetail(ns, dicIstioTypeToGVK['AuthorizationPolicy'], ap.metadata.name, cluster)
+              API.deleteIstioConfigDetail(ns, dicTypeToGVK[gvkType.AuthorizationPolicy], ap.metadata.name, cluster)
             )
             .concat(
-              sdsP.map(sc => API.deleteIstioConfigDetail(ns, dicIstioTypeToGVK['Sidecar'], sc.metadata.name, cluster))
+              sdsP.map(sc => API.deleteIstioConfigDetail(ns, dicTypeToGVK[gvkType.Sidecar], sc.metadata.name, cluster))
             )
         )
         .then(_ => {
@@ -224,10 +224,10 @@ export class OverviewTrafficPolicies extends React.Component<OverviewTrafficPoli
           'trafficPoliciesCreate',
           aps
             .map(ap =>
-              API.createIstioConfigDetail(ns, dicIstioTypeToGVK['AuthorizationPolicy'], JSON.stringify(ap), cluster)
+              API.createIstioConfigDetail(ns, dicTypeToGVK[gvkType.AuthorizationPolicy], JSON.stringify(ap), cluster)
             )
             .concat(
-              sds.map(sc => API.createIstioConfigDetail(ns, dicIstioTypeToGVK['Sidecar'], JSON.stringify(sc), cluster))
+              sds.map(sc => API.createIstioConfigDetail(ns, dicTypeToGVK[gvkType.Sidecar], JSON.stringify(sc), cluster))
             )
         )
         .then(results => {
@@ -262,20 +262,20 @@ export class OverviewTrafficPolicies extends React.Component<OverviewTrafficPoli
 
     this.state.authorizationPolicies.length > 0 &&
       items.push({
-        objectGVK: dicIstioTypeToGVK['AuthorizationPolicy'],
+        objectGVK: dicTypeToGVK[gvkType.AuthorizationPolicy],
         items: this.state.authorizationPolicies,
         title: 'Authorization Policies'
       });
 
     this.state.sidecars.length > 0 &&
-      items.push({ objectGVK: dicIstioTypeToGVK['Sidecar'], items: this.state.sidecars, title: 'Sidecars' });
+      items.push({ objectGVK: dicTypeToGVK[gvkType.Sidecar], items: this.state.sidecars, title: 'Sidecars' });
 
     return items;
   };
 
   onConfirmPreviewPoliciesModal = (items: ConfigPreviewItem[]): void => {
-    const aps = items.filter(i => getGVKTypeString(i.objectGVK) === getGVKTypeString('AuthorizationPolicy'))[0];
-    const sds = items.filter(i => getGVKTypeString(i.objectGVK) === getGVKTypeString('Sidecar'))[0];
+    const aps = items.filter(i => getGVKTypeString(i.objectGVK) === getGVKTypeString(gvkType.AuthorizationPolicy))[0];
+    const sds = items.filter(i => getGVKTypeString(i.objectGVK) === getGVKTypeString(gvkType.Sidecar))[0];
 
     this.setState(
       {
diff --git a/frontend/src/pages/ServiceDetails/ServiceDetailsPage.tsx b/frontend/src/pages/ServiceDetails/ServiceDetailsPage.tsx
index 84157508e..cdd385391 100644
--- a/frontend/src/pages/ServiceDetails/ServiceDetailsPage.tsx
+++ b/frontend/src/pages/ServiceDetails/ServiceDetailsPage.tsx
@@ -35,6 +35,7 @@ import { durationSelector } from 'store/Selectors';
 import { basicTabStyle } from 'styles/TabStyles';
 import { serverConfig } from 'config';
 import { getGVKTypeString } from '../../utils/IstioConfigUtils';
+import { gvkType } from '../../types/IstioConfigList';
 
 type ServiceDetailsState = {
   cluster?: string;
@@ -119,7 +120,7 @@ class ServiceDetailsPageComponent extends React.Component<ServiceDetailsProps, S
         'gateways',
         API.getIstioConfig(
           this.props.serviceId.namespace,
-          [getGVKTypeString('Gateway'), getGVKTypeString('K8sGateway')],
+          [getGVKTypeString(gvkType.Gateway), getGVKTypeString(gvkType.K8sGateway)],
           false,
           '',
           '',
@@ -127,8 +128,8 @@ class ServiceDetailsPageComponent extends React.Component<ServiceDetailsProps, S
         )
       )
       .then(response => {
-        this.setState({ gateways: response.data.resources[getGVKTypeString('Gateway')] });
-        this.setState({ k8sGateways: response.data.resources[getGVKTypeString('K8sGateway')] });
+        this.setState({ gateways: response.data.resources[getGVKTypeString(gvkType.Gateway)] });
+        this.setState({ k8sGateways: response.data.resources[getGVKTypeString(gvkType.K8sGateway)] });
       })
       .catch(gwError => {
         AlertUtils.addError('Could not fetch Gateways list.', gwError);
@@ -157,10 +158,17 @@ class ServiceDetailsPageComponent extends React.Component<ServiceDetailsProps, S
         this.setState({ error: msg });
       });
 
-    API.getIstioConfig(this.props.serviceId.namespace, [getGVKTypeString('PeerAuthentication')], false, '', '', cluster)
+    API.getIstioConfig(
+      this.props.serviceId.namespace,
+      [getGVKTypeString(gvkType.PeerAuthentication)],
+      false,
+      '',
+      '',
+      cluster
+    )
       .then(results => {
         this.setState({
-          peerAuthentications: results.data.resources[getGVKTypeString('PeerAuthentication')]
+          peerAuthentications: results.data.resources[getGVKTypeString(gvkType.PeerAuthentication)]
         });
       })
       .catch(error => {
diff --git a/frontend/src/pages/WorkloadDetails/WorkloadDescription.tsx b/frontend/src/pages/WorkloadDetails/WorkloadDescription.tsx
index 61da158b4..903ad4ecf 100644
--- a/frontend/src/pages/WorkloadDetails/WorkloadDescription.tsx
+++ b/frontend/src/pages/WorkloadDetails/WorkloadDescription.tsx
@@ -15,12 +15,13 @@ import { MissingSidecar } from '../../components/MissingSidecar/MissingSidecar';
 import { PFBadge, PFBadges } from '../../components/Pf/PfBadges';
 import { MissingLabel } from '../../components/MissingLabel/MissingLabel';
 import { MissingAuthPolicy } from 'components/MissingAuthPolicy/MissingAuthPolicy';
-import { hasMissingAuthPolicy } from 'utils/IstioConfigUtils';
+import { getGVKTypeString, hasMissingAuthPolicy, isGVKSupported } from 'utils/IstioConfigUtils';
 import { DetailDescription } from '../../components/DetailDescription/DetailDescription';
 import { isWaypoint } from '../../helpers/LabelFilterHelper';
 import { AmbientLabel, tooltipMsgType } from '../../components/Ambient/AmbientLabel';
-import { validationKey } from '../../types/IstioConfigList';
+import { gvkType, validationKey } from '../../types/IstioConfigList';
 import { infoStyle } from 'styles/IconStyle';
+import { addInfo } from 'utils/AlertUtils';
 import { classes } from 'typestyle';
 
 type WorkloadDescriptionProps = {
@@ -30,12 +31,16 @@ type WorkloadDescriptionProps = {
 };
 
 const resourceListStyle = kialiStyle({
-  marginBottom: '0.75rem',
+  display: 'flex',
   $nest: {
-    '& > ul > li span': {
-      float: 'left',
-      width: '125px',
-      fontWeight: 700
+    '& > ul > li': {
+      display: 'flex',
+      $nest: {
+        '& span': {
+          minWidth: '125px',
+          fontWeight: 700
+        }
+      }
     }
   }
 });
@@ -80,11 +85,20 @@ export const WorkloadDescription: React.FC<WorkloadDescriptionProps> = (props: W
   workload.services?.forEach(s => services.push(s.name));
 
   const isTemplateLabels =
-    ['Deployment', 'ReplicaSet', 'ReplicationController', 'DeploymentConfig', 'StatefulSet'].indexOf(workload.type) >=
-    0;
+    [
+      getGVKTypeString(gvkType.Deployment),
+      getGVKTypeString(gvkType.ReplicaSet),
+      getGVKTypeString(gvkType.ReplicationController),
+      getGVKTypeString(gvkType.DeploymentConfig),
+      getGVKTypeString(gvkType.StatefulSet)
+    ].indexOf(getGVKTypeString(workload.gvk)) >= 0;
 
   const runtimes = (workload.runtimes ?? []).map(r => r.name).filter(name => name !== '');
 
+  if (!isGVKSupported(workload.gvk)) {
+    addInfo('This type of workload is not fully supported by Kiali, only limited information is available for display');
+  }
+
   const workloadProperties = (
     <>
       <div key="properties-list" className={resourceListStyle}>
@@ -96,9 +110,16 @@ export const WorkloadDescription: React.FC<WorkloadDescriptionProps> = (props: W
             </li>
           )}
 
+          {!isGVKSupported(workload.gvk) && (
+            <li>
+              <span>API Version</span>
+              {`${workload.gvk.Group}.${workload.gvk.Version}`}
+            </li>
+          )}
+
           <li>
             <span>Type</span>
-            {workload.type ? workload.type : 'N/A'}
+            {workload.gvk.Kind || 'N/A'}
           </li>
 
           <li>
diff --git a/frontend/src/pages/WorkloadDetails/WorkloadDetailsPage.tsx b/frontend/src/pages/WorkloadDetails/WorkloadDetailsPage.tsx
index a501baf81..aba1d4e90 100644
--- a/frontend/src/pages/WorkloadDetails/WorkloadDetailsPage.tsx
+++ b/frontend/src/pages/WorkloadDetails/WorkloadDetailsPage.tsx
@@ -306,7 +306,7 @@ class WorkloadDetailsPageComponent extends React.Component<WorkloadDetailsPagePr
                     app={app}
                     version={version}
                     workload={this.state.workload!.name}
-                    workloadType={this.state.workload!.type}
+                    workloadType={this.state.workload!.gvk.Kind}
                     template={dashboard.template}
                   />
                 </Tab>
diff --git a/frontend/src/pages/WorkloadDetails/WorkloadInfo.tsx b/frontend/src/pages/WorkloadDetails/WorkloadInfo.tsx
index f0fc2ab48..c35a98772 100644
--- a/frontend/src/pages/WorkloadDetails/WorkloadInfo.tsx
+++ b/frontend/src/pages/WorkloadDetails/WorkloadInfo.tsx
@@ -12,7 +12,7 @@ import { RenderComponentScroll } from '../../components/Nav/Page';
 import { GraphDataSource } from '../../services/GraphDataSource';
 import { DurationInSeconds } from 'types/Common';
 import { isIstioNamespace, serverConfig } from '../../config/ServerConfig';
-import { IstioConfigList, toIstioItems } from '../../types/IstioConfigList';
+import { gvkType, IstioConfigList, toIstioItems } from '../../types/IstioConfigList';
 import { WorkloadPods } from './WorkloadPods';
 import { GraphEdgeTapEvent } from '../../components/CytoscapeGraph/CytoscapeGraph';
 import { location, router, URLParam } from '../../app/History';
@@ -44,12 +44,12 @@ const tabName = 'list';
 const defaultTab = 'pods';
 
 const workloadIstioResources = [
-  getGVKTypeString('Gateway'),
-  getGVKTypeString('AuthorizationPolicy'),
-  getGVKTypeString('PeerAuthentication'),
-  getGVKTypeString('Sidecar'),
-  getGVKTypeString('RequestAuthentication'),
-  getGVKTypeString('EnvoyFilter')
+  getGVKTypeString(gvkType.Gateway),
+  getGVKTypeString(gvkType.AuthorizationPolicy),
+  getGVKTypeString(gvkType.PeerAuthentication),
+  getGVKTypeString(gvkType.Sidecar),
+  getGVKTypeString(gvkType.RequestAuthentication),
+  getGVKTypeString(gvkType.EnvoyFilter)
 ];
 
 export class WorkloadInfo extends React.Component<WorkloadInfoProps, WorkloadInfoState> {
diff --git a/frontend/src/pages/WorkloadList/FiltersAndSorts.ts b/frontend/src/pages/WorkloadList/FiltersAndSorts.ts
index beafa15d6..89d7920d3 100644
--- a/frontend/src/pages/WorkloadList/FiltersAndSorts.ts
+++ b/frontend/src/pages/WorkloadList/FiltersAndSorts.ts
@@ -6,7 +6,7 @@ import {
   AllFilterTypes,
   ToggleType
 } from '../../types/Filters';
-import { WorkloadListItem, WorkloadType } from '../../types/Workload';
+import { WorkloadListItem } from '../../types/Workload';
 import { hasMissingSidecar } from 'components/VirtualList/Config';
 import { SortField } from '../../types/SortFilters';
 import { hasHealth } from '../../types/Health';
@@ -26,6 +26,7 @@ import { istioConfigTypeFilter } from '../IstioConfigList/FiltersAndSorts';
 import { compareObjectReferences } from '../AppList/FiltersAndSorts';
 import { serverConfig } from 'config';
 import { getGVKTypeString, istioTypesToGVKString } from '../../utils/IstioConfigUtils';
+import { dicTypeToGVK } from '../../types/IstioConfigList';
 
 const missingLabels = (r: WorkloadListItem): number => {
   return r.appLabel && r.versionLabel ? 0 : r.appLabel || r.versionLabel ? 1 : 2;
@@ -57,7 +58,7 @@ export const sortFields: SortField<WorkloadListItem>[] = [
     title: 'Workload Type',
     isNumeric: false,
     param: 'wt',
-    compare: (a: WorkloadListItem, b: WorkloadListItem) => a.type.localeCompare(b.type)
+    compare: (a: WorkloadListItem, b: WorkloadListItem) => a.gvk.Kind.localeCompare(b.gvk.Kind)
   },
   {
     id: 'details',
@@ -236,40 +237,40 @@ const workloadTypeFilter: FilterType = {
   action: FILTER_ACTION_APPEND,
   filterValues: [
     {
-      id: WorkloadType.CronJob,
-      title: WorkloadType.CronJob
+      id: dicTypeToGVK.CronJob.Kind,
+      title: dicTypeToGVK.CronJob.Kind
     },
     {
-      id: WorkloadType.DaemonSet,
-      title: WorkloadType.DaemonSet
+      id: dicTypeToGVK.DaemonSet.Kind,
+      title: dicTypeToGVK.DaemonSet.Kind
     },
     {
-      id: WorkloadType.Deployment,
-      title: WorkloadType.Deployment
+      id: dicTypeToGVK.Deployment.Kind,
+      title: dicTypeToGVK.Deployment.Kind
     },
     {
-      id: WorkloadType.DeploymentConfig,
-      title: WorkloadType.DeploymentConfig
+      id: dicTypeToGVK.DeploymentConfig.Kind,
+      title: dicTypeToGVK.DeploymentConfig.Kind
     },
     {
-      id: WorkloadType.Job,
-      title: WorkloadType.Job
+      id: dicTypeToGVK.Job.Kind,
+      title: dicTypeToGVK.Job.Kind
     },
     {
-      id: WorkloadType.Pod,
-      title: WorkloadType.Pod
+      id: dicTypeToGVK.Pod.Kind,
+      title: dicTypeToGVK.Pod.Kind
     },
     {
-      id: WorkloadType.ReplicaSet,
-      title: WorkloadType.ReplicaSet
+      id: dicTypeToGVK.ReplicaSet.Kind,
+      title: dicTypeToGVK.ReplicaSet.Kind
     },
     {
-      id: WorkloadType.ReplicationController,
-      title: WorkloadType.ReplicationController
+      id: dicTypeToGVK.ReplicationController.Kind,
+      title: dicTypeToGVK.ReplicationController.Kind
     },
     {
-      id: WorkloadType.StatefulSet,
-      title: WorkloadType.StatefulSet
+      id: dicTypeToGVK.StatefulSet.Kind,
+      title: dicTypeToGVK.StatefulSet.Kind
     }
   ]
 };
@@ -299,7 +300,7 @@ const filterByType = (items: WorkloadListItem[], filter: string[]): WorkloadList
   if (filter && filter.length === 0) {
     return items;
   }
-  return items.filter(item => includeName(item.type, filter));
+  return items.filter(item => includeName(item.gvk.Kind, filter));
 };
 
 const filterByLabelPresence = (
diff --git a/frontend/src/pages/WorkloadList/WorkloadListPage.tsx b/frontend/src/pages/WorkloadList/WorkloadListPage.tsx
index 623cc2be7..5f37dc83d 100644
--- a/frontend/src/pages/WorkloadList/WorkloadListPage.tsx
+++ b/frontend/src/pages/WorkloadList/WorkloadListPage.tsx
@@ -120,7 +120,7 @@ class WorkloadListPageComponent extends FilterComponent.Component<
         namespace: deployment.namespace,
         name: deployment.name,
         instanceType: InstanceType.Workload,
-        type: deployment.type,
+        gvk: deployment.gvk,
         appLabel: deployment.appLabel,
         versionLabel: deployment.versionLabel,
         istioSidecar: deployment.istioSidecar,
diff --git a/frontend/src/services/Api.ts b/frontend/src/services/Api.ts
index 0bba276eb..5e733a607 100644
--- a/frontend/src/services/Api.ts
+++ b/frontend/src/services/Api.ts
@@ -24,7 +24,8 @@ import {
   IstioPermissionsQuery
 } from '../types/IstioConfigDetails';
 import {
-  dicIstioTypeToGVK,
+  dicTypeToGVK,
+  gvkType,
   IstioConfigList,
   IstioConfigListQuery,
   IstioConfigsMapQuery
@@ -70,6 +71,7 @@ import {
 } from '../types/Workload';
 import { CertsInfo } from 'types/CertsInfo';
 import { ApiError, ApiResponse } from 'types/Api';
+import { getGVKTypeString } from '../utils/IstioConfigUtils';
 
 export const ANONYMOUS_USER = 'anonymous';
 
@@ -1020,12 +1022,12 @@ export const getWorkload = (
 export const updateWorkload = (
   namespace: string,
   name: string,
-  type: string,
+  type: GroupVersionKind | gvkType,
   jsonPatch: string,
   patchType?: string,
   cluster?: string
 ): Promise<ApiResponse<string>> => {
-  const params: QueryParams<WorkloadUpdateQuery> = { type: type };
+  const params: QueryParams<WorkloadUpdateQuery> = { gvk: getGVKTypeString(type) };
 
   if (patchType) {
     params.patchType = patchType;
@@ -1284,7 +1286,7 @@ export function deleteServiceTrafficRouting(
     deletePromises.push(
       deleteIstioConfigDetail(
         vs.metadata.namespace ?? '',
-        dicIstioTypeToGVK['VirtualService'],
+        dicTypeToGVK[gvkType.VirtualService],
         vs.metadata.name,
         cluster
       )
@@ -1295,7 +1297,7 @@ export function deleteServiceTrafficRouting(
     deletePromises.push(
       deleteIstioConfigDetail(
         k8sr.metadata.namespace ?? '',
-        dicIstioTypeToGVK['K8sHTTPRoute'],
+        dicTypeToGVK[gvkType.K8sHTTPRoute],
         k8sr.metadata.name,
         cluster
       )
@@ -1306,7 +1308,7 @@ export function deleteServiceTrafficRouting(
     deletePromises.push(
       deleteIstioConfigDetail(
         k8sr.metadata.namespace ?? '',
-        dicIstioTypeToGVK['K8sGRPCRoute'],
+        dicTypeToGVK[gvkType.K8sGRPCRoute],
         k8sr.metadata.name,
         cluster
       )
@@ -1316,7 +1318,7 @@ export function deleteServiceTrafficRouting(
     deletePromises.push(
       deleteIstioConfigDetail(
         dr.metadata.namespace ?? '',
-        dicIstioTypeToGVK['DestinationRule'],
+        dicTypeToGVK[gvkType.DestinationRule],
         dr.metadata.name,
         cluster
       )
@@ -1325,7 +1327,7 @@ export function deleteServiceTrafficRouting(
     const paName = dr.hasPeerAuthentication();
     if (!!paName) {
       deletePromises.push(
-        deleteIstioConfigDetail(dr.metadata.namespace ?? '', dicIstioTypeToGVK['PeerAuthentication'], paName, cluster)
+        deleteIstioConfigDetail(dr.metadata.namespace ?? '', dicTypeToGVK[gvkType.PeerAuthentication], paName, cluster)
       );
     }
   });
diff --git a/frontend/src/services/__mockData__/getServiceDetail.ts b/frontend/src/services/__mockData__/getServiceDetail.ts
index 3c640318b..2d5d5c907 100644
--- a/frontend/src/services/__mockData__/getServiceDetail.ts
+++ b/frontend/src/services/__mockData__/getServiceDetail.ts
@@ -1,6 +1,6 @@
 import { ServiceDetailsInfo } from '../../types/ServiceInfo';
 import { ValidationTypes } from '../../types/IstioObjects';
-import { dicIstioTypeToGVK } from '../../types/IstioConfigList';
+import { dicTypeToGVK, gvkType } from '../../types/IstioConfigList';
 
 export const SERVICE_DETAILS: ServiceDetailsInfo = {
   service: {
@@ -136,7 +136,7 @@ export const SERVICE_DETAILS: ServiceDetailsInfo = {
     'networking.istio.io/v1, Kind=DestinationRule': {
       reviews: {
         name: 'details',
-        objectGVK: dicIstioTypeToGVK['DestinationRule'],
+        objectGVK: dicTypeToGVK[gvkType.DestinationRule],
         valid: false,
         checks: [
           {
diff --git a/frontend/src/types/IstioConfigList.ts b/frontend/src/types/IstioConfigList.ts
index 60086372e..9a28a4017 100644
--- a/frontend/src/types/IstioConfigList.ts
+++ b/frontend/src/types/IstioConfigList.ts
@@ -46,30 +46,76 @@ export interface IstioConfigsMapQuery extends IstioConfigListQuery {
   namespaces?: string;
 }
 
-export const dicIstioTypeToGVK: { [key: string]: GroupVersionKind } = {
-  AuthorizationPolicy: { Group: 'security.istio.io', Version: 'v1', Kind: 'AuthorizationPolicy' },
-  PeerAuthentication: { Group: 'security.istio.io', Version: 'v1', Kind: 'PeerAuthentication' },
-  RequestAuthentication: { Group: 'security.istio.io', Version: 'v1', Kind: 'RequestAuthentication' },
-
-  DestinationRule: { Group: 'networking.istio.io', Version: 'v1', Kind: 'DestinationRule' },
-  Gateway: { Group: 'networking.istio.io', Version: 'v1', Kind: 'Gateway' },
-  EnvoyFilter: { Group: 'networking.istio.io', Version: 'v1alpha3', Kind: 'EnvoyFilter' },
-  Sidecar: { Group: 'networking.istio.io', Version: 'v1', Kind: 'Sidecar' },
-  ServiceEntry: { Group: 'networking.istio.io', Version: 'v1', Kind: 'ServiceEntry' },
-  VirtualService: { Group: 'networking.istio.io', Version: 'v1', Kind: 'VirtualService' },
-  WorkloadEntry: { Group: 'networking.istio.io', Version: 'v1', Kind: 'WorkloadEntry' },
-  WorkloadGroup: { Group: 'networking.istio.io', Version: 'v1', Kind: 'WorkloadGroup' },
-
-  WasmPlugin: { Group: 'extensions.istio.io', Version: 'v1alpha1', Kind: 'WasmPlugin' },
-  Telemetry: { Group: 'telemetry.istio.io', Version: 'v1', Kind: 'Telemetry' },
-
-  K8sGateway: { Group: 'gateway.networking.k8s.io', Version: 'v1', Kind: 'Gateway' },
-  K8sGatewayClass: { Group: 'gateway.networking.k8s.io', Version: 'v1', Kind: 'GatewayClass' },
-  K8sGRPCRoute: { Group: 'gateway.networking.k8s.io', Version: 'v1', Kind: 'GRPCRoute' },
-  K8sHTTPRoute: { Group: 'gateway.networking.k8s.io', Version: 'v1', Kind: 'HTTPRoute' },
-  K8sReferenceGrant: { Group: 'gateway.networking.k8s.io', Version: 'v1', Kind: 'ReferenceGrant' },
-  K8sTCPRoute: { Group: 'gateway.networking.k8s.io', Version: 'v1alpha2', Kind: 'TCPRoute' },
-  K8sTLSRoute: { Group: 'gateway.networking.k8s.io', Version: 'v1alpha2', Kind: 'TLSRoute' }
+export enum gvkType {
+  AuthorizationPolicy = 'AuthorizationPolicy',
+  PeerAuthentication = 'PeerAuthentication',
+  RequestAuthentication = 'RequestAuthentication',
+
+  DestinationRule = 'DestinationRule',
+  Gateway = 'Gateway',
+  EnvoyFilter = 'EnvoyFilter',
+  Sidecar = 'Sidecar',
+  ServiceEntry = 'ServiceEntry',
+  VirtualService = 'VirtualService',
+  WorkloadEntry = 'WorkloadEntry',
+  WorkloadGroup = 'WorkloadGroup',
+
+  WasmPlugin = 'WasmPlugin',
+  Telemetry = 'Telemetry',
+
+  K8sGateway = 'K8sGateway',
+  K8sGatewayClass = 'K8sGatewayClass',
+  K8sGRPCRoute = 'K8sGRPCRoute',
+  K8sHTTPRoute = 'K8sHTTPRoute',
+  K8sReferenceGrant = 'K8sReferenceGrant',
+  K8sTCPRoute = 'K8sTCPRoute',
+  K8sTLSRoute = 'K8sTLSRoute',
+
+  CronJob = 'CronJob',
+  DaemonSet = 'DaemonSet',
+  Deployment = 'Deployment',
+  DeploymentConfig = 'DeploymentConfig',
+  Job = 'Job',
+  Pod = 'Pod',
+  ReplicaSet = 'ReplicaSet',
+  ReplicationController = 'ReplicationController',
+  StatefulSet = 'StatefulSet'
+}
+
+export const dicTypeToGVK: { [key in gvkType]: GroupVersionKind } = {
+  [gvkType.AuthorizationPolicy]: { Group: 'security.istio.io', Version: 'v1', Kind: gvkType.AuthorizationPolicy },
+  [gvkType.PeerAuthentication]: { Group: 'security.istio.io', Version: 'v1', Kind: gvkType.PeerAuthentication },
+  [gvkType.RequestAuthentication]: { Group: 'security.istio.io', Version: 'v1', Kind: gvkType.RequestAuthentication },
+
+  [gvkType.DestinationRule]: { Group: 'networking.istio.io', Version: 'v1', Kind: gvkType.DestinationRule },
+  [gvkType.Gateway]: { Group: 'networking.istio.io', Version: 'v1', Kind: gvkType.Gateway },
+  [gvkType.EnvoyFilter]: { Group: 'networking.istio.io', Version: 'v1alpha3', Kind: gvkType.EnvoyFilter },
+  [gvkType.Sidecar]: { Group: 'networking.istio.io', Version: 'v1', Kind: gvkType.Sidecar },
+  [gvkType.ServiceEntry]: { Group: 'networking.istio.io', Version: 'v1', Kind: gvkType.ServiceEntry },
+  [gvkType.VirtualService]: { Group: 'networking.istio.io', Version: 'v1', Kind: gvkType.VirtualService },
+  [gvkType.WorkloadEntry]: { Group: 'networking.istio.io', Version: 'v1', Kind: gvkType.WorkloadEntry },
+  [gvkType.WorkloadGroup]: { Group: 'networking.istio.io', Version: 'v1', Kind: gvkType.WorkloadGroup },
+
+  [gvkType.WasmPlugin]: { Group: 'extensions.istio.io', Version: 'v1alpha1', Kind: gvkType.WasmPlugin },
+  [gvkType.Telemetry]: { Group: 'telemetry.istio.io', Version: 'v1', Kind: gvkType.Telemetry },
+
+  [gvkType.K8sGateway]: { Group: 'gateway.networking.k8s.io', Version: 'v1', Kind: 'Gateway' },
+  [gvkType.K8sGatewayClass]: { Group: 'gateway.networking.k8s.io', Version: 'v1', Kind: 'GatewayClass' },
+  [gvkType.K8sGRPCRoute]: { Group: 'gateway.networking.k8s.io', Version: 'v1', Kind: 'GRPCRoute' },
+  [gvkType.K8sHTTPRoute]: { Group: 'gateway.networking.k8s.io', Version: 'v1', Kind: 'HTTPRoute' },
+  [gvkType.K8sReferenceGrant]: { Group: 'gateway.networking.k8s.io', Version: 'v1', Kind: 'ReferenceGrant' },
+  [gvkType.K8sTCPRoute]: { Group: 'gateway.networking.k8s.io', Version: 'v1alpha2', Kind: 'TCPRoute' },
+  [gvkType.K8sTLSRoute]: { Group: 'gateway.networking.k8s.io', Version: 'v1alpha2', Kind: 'TLSRoute' },
+
+  [gvkType.CronJob]: { Group: 'batch', Version: 'v1', Kind: 'CronJob' },
+  [gvkType.DaemonSet]: { Group: 'apps', Version: 'v1', Kind: 'DaemonSet' },
+  [gvkType.Deployment]: { Group: 'apps', Version: 'v1', Kind: 'Deployment' },
+  [gvkType.DeploymentConfig]: { Group: 'apps.openshift.io', Version: 'v1', Kind: 'DeploymentConfig' },
+  [gvkType.Job]: { Group: 'batch', Version: 'v1', Kind: 'Job' },
+  [gvkType.Pod]: { Group: '', Version: 'v1', Kind: 'Pod' },
+  [gvkType.ReplicaSet]: { Group: 'apps', Version: 'v1', Kind: 'ReplicaSet' },
+  [gvkType.ReplicationController]: { Group: '', Version: 'v1', Kind: 'ReplicationController' },
+  [gvkType.StatefulSet]: { Group: 'apps', Version: 'v1', Kind: 'StatefulSet' }
 };
 
 export function validationKey(name: string, namespace?: string): string {
@@ -101,9 +147,9 @@ export const filterByNamespaces = (unfiltered: IstioConfigList, namespaces: stri
   const namespaceSet = new Set(namespaces);
   const filteredResources: { [key: string]: any[] } = {};
 
-  // Iterate over dicIstioTypeToGVK to dynamically filter each resource by namespace
-  Object.keys(dicIstioTypeToGVK).forEach(key => {
-    const resourceKey = getGVKTypeString(key);
+  // Iterate over dicTypeToGVK to dynamically filter each resource by namespace
+  Object.values(dicTypeToGVK).forEach(value => {
+    const resourceKey = getGVKTypeString(value);
 
     // Check if the resource exists in the unfiltered list, then filter by namespace
     if (unfiltered.resources[resourceKey]) {
@@ -127,9 +173,9 @@ export const filterByName = (unfiltered: IstioConfigList, names: string[]): Isti
 
   const filteredResources: { [key: string]: any[] } = {};
 
-  // Iterate over the dicIstioTypeToGVK to access each resource type dynamically
-  Object.keys(dicIstioTypeToGVK).forEach(key => {
-    const resourceKey = getGVKTypeString(key);
+  // Iterate over the dicTypeToGVK to access each resource type dynamically
+  Object.values(dicTypeToGVK).forEach(value => {
+    const resourceKey = getGVKTypeString(value);
 
     // Check if the resource exists in the unfiltered list, then filter by names
     if (unfiltered.resources[resourceKey]) {
diff --git a/frontend/src/types/Workload.ts b/frontend/src/types/Workload.ts
index 0858be83f..31d563138 100644
--- a/frontend/src/types/Workload.ts
+++ b/frontend/src/types/Workload.ts
@@ -1,5 +1,5 @@
 import { WorkloadHealth, WorkloadHealthResponse } from './Health';
-import { ObjectReference, Pod, Service, Validations } from './IstioObjects';
+import { GroupVersionKind, ObjectReference, Pod, Service, Validations } from './IstioObjects';
 import { InstanceType } from 'types/Common';
 
 export type WorkloadId = {
@@ -14,6 +14,7 @@ export interface Workload {
   availableReplicas: Number;
   cluster?: string;
   createdAt: string;
+  gvk: GroupVersionKind;
   health?: WorkloadHealthResponse;
   instanceType: InstanceType.Workload;
   isAmbient: boolean;
@@ -28,7 +29,6 @@ export interface Workload {
   resourceVersion: string;
   runtimes: Runtime[];
   services: Service[];
-  type: string;
   validations?: Validations;
   versionLabel: boolean;
   waypointWorkloads: Workload[];
@@ -40,6 +40,7 @@ export const emptyWorkload: Workload = {
   appLabel: false,
   availableReplicas: 0,
   createdAt: '',
+  gvk: { Group: '', Version: '', Kind: '' },
   isAmbient: false,
   isGateway: false,
   istioSidecar: true, // true until proven otherwise
@@ -52,27 +53,15 @@ export const emptyWorkload: Workload = {
   resourceVersion: '',
   runtimes: [],
   services: [],
-  type: '',
   versionLabel: false,
   waypointWorkloads: []
 };
 
-export const WorkloadType = {
-  CronJob: 'CronJob',
-  DaemonSet: 'DaemonSet',
-  Deployment: 'Deployment',
-  DeploymentConfig: 'DeploymentConfig',
-  Job: 'Job',
-  Pod: 'Pod',
-  ReplicaSet: 'ReplicaSet',
-  ReplicationController: 'ReplicationController',
-  StatefulSet: 'StatefulSet'
-};
-
 export interface WorkloadListItem {
   additionalDetailSample?: AdditionalItem;
   appLabel: boolean;
   cluster?: string;
+  gvk: GroupVersionKind;
   health: WorkloadHealth;
   instanceType: InstanceType.Workload;
   isAmbient: boolean;
@@ -83,7 +72,6 @@ export interface WorkloadListItem {
   name: string;
   namespace: string;
   notCoveredAuthPolicy: boolean;
-  type: string;
   versionLabel: boolean;
 }
 
@@ -94,8 +82,8 @@ export interface WorkloadQuery {
 }
 
 export interface WorkloadUpdateQuery {
+  gvk: string;
   patchType?: string;
-  type: string;
 }
 
 export interface WorkloadListQuery {
diff --git a/frontend/src/utils/IstioConfigUtils.ts b/frontend/src/utils/IstioConfigUtils.ts
index 4008fbe69..21cdf75e6 100644
--- a/frontend/src/utils/IstioConfigUtils.ts
+++ b/frontend/src/utils/IstioConfigUtils.ts
@@ -9,7 +9,7 @@ import {
   Validations
 } from '../types/IstioObjects';
 import _ from 'lodash';
-import { dicIstioTypeToGVK, IstioConfigItem } from 'types/IstioConfigList';
+import { dicTypeToGVK, gvkType, IstioConfigItem } from 'types/IstioConfigList';
 
 export const mergeJsonPatch = (objectModified: object, object?: object): object => {
   if (!object) {
@@ -194,14 +194,18 @@ export function getIstioObjectGVK(apiVersion?: string, kind?: string): GroupVers
   const parts = apiVersion.split('/');
   if (parts.length !== 2) {
     // should not happen, but not the best way, only an alternative
-    return dicIstioTypeToGVK[kind];
+    return dicTypeToGVK[kind];
   }
   return { Group: parts[0], Version: parts[1], Kind: kind! };
 }
 
-export function getGVKTypeString(gvk: GroupVersionKind | string): string {
+export function getGVKTypeString(gvk: GroupVersionKind | gvkType): string {
   if (typeof gvk === 'string') {
-    return gvkToString(dicIstioTypeToGVK[gvk]);
+    const gvkEntry = dicTypeToGVK[gvk];
+    if (!gvkEntry) {
+      throw new Error(`GVK type '${gvk}' not found in dicTypeToGVK.`);
+    }
+    return gvkToString(gvkEntry);
   } else {
     return gvkToString(gvk);
   }
@@ -243,6 +247,10 @@ export function kindToStringIncludeK8s(apiVersion?: string, kind?: string): stri
 
 export function istioTypesToGVKString(istioTypes: string[]): string[] {
   return istioTypes.map(type => {
-    return gvkToString(dicIstioTypeToGVK[type]);
+    return gvkToString(dicTypeToGVK[type]);
   });
 }
+
+export function isGVKSupported(gvk: GroupVersionKind): boolean {
+  return getGVKTypeString(gvk) === getGVKTypeString(gvkType[gvk.Kind]);
+}
diff --git a/graph/telemetry/istio/appender/istio_details.go b/graph/telemetry/istio/appender/istio_details.go
index f5f3538d7..479fb4e79 100644
--- a/graph/telemetry/istio/appender/istio_details.go
+++ b/graph/telemetry/istio/appender/istio_details.go
@@ -368,7 +368,7 @@ func (a IstioAppender) getIstioComponentWorkloads(component string, globalInfo *
 
 		// Find Istio component deployments
 		for _, workload := range wList.Workloads {
-			if workload.Type == "Deployment" {
+			if workload.WorkloadGVK == kubernetes.Deployments {
 				if labelValue, ok := workload.Labels["operator.istio.io/component"]; ok && labelValue == component {
 					componentWorkloads[key] = append(componentWorkloads[key], workload)
 				}
@@ -388,7 +388,7 @@ func (a IstioAppender) getGatewayAPIWorkloads(globalInfo *graph.GlobalInfo) map[
 
 		// Find Istio managed Gateway API deployments
 		for _, workload := range wList.Workloads {
-			if workload.Type == "Deployment" {
+			if workload.WorkloadGVK == kubernetes.Deployments {
 				if _, ok := workload.Labels["istio.io/gateway-name"]; ok {
 					managedWorkloads[key] = append(managedWorkloads[key], workload)
 				}
diff --git a/handlers/dashboards.go b/handlers/dashboards.go
index db4ac3d74..af5aaf780 100644
--- a/handlers/dashboards.go
+++ b/handlers/dashboards.go
@@ -45,7 +45,7 @@ func CustomDashboard(conf *config.Config, grafana *grafana.Service) http.Handler
 
 		var wkd *models.Workload
 		if params.Workload != "" {
-			wkd, err = layer.Workload.GetWorkload(r.Context(), business.WorkloadCriteria{Cluster: cluster, Namespace: namespace, WorkloadName: params.Workload, WorkloadType: params.WorkloadType, IncludeServices: false})
+			wkd, err = layer.Workload.GetWorkload(r.Context(), business.WorkloadCriteria{Cluster: cluster, Namespace: namespace, WorkloadName: params.Workload, WorkloadGVK: params.WorkloadGVK, IncludeServices: false})
 			if err != nil {
 				if errors.IsNotFound(err) {
 					RespondWithError(w, http.StatusNotFound, err.Error())
diff --git a/handlers/workloads.go b/handlers/workloads.go
index 15bbfa8a7..98b42412c 100644
--- a/handlers/workloads.go
+++ b/handlers/workloads.go
@@ -9,12 +9,15 @@ import (
 	"strings"
 	"sync"
 
+	"k8s.io/apimachinery/pkg/runtime/schema"
+
 	"github.com/gorilla/mux"
 
 	"github.com/kiali/kiali/business"
 	"github.com/kiali/kiali/config"
 	"github.com/kiali/kiali/log"
 	"github.com/kiali/kiali/models"
+	"github.com/kiali/kiali/util"
 )
 
 // workloadParams holds the path and query parameters for WorkloadList and WorkloadDetails
@@ -28,20 +31,19 @@ type workloadParams struct {
 	Namespace    string `json:"namespace"`
 	WorkloadName string `json:"workload"`
 	// in: query
-	WorkloadType string `json:"type"`
+	WorkloadGVK schema.GroupVersionKind `json:"workloadGVK"`
 	// Optional
 	ClusterName           string `json:"clusterName,omitempty"`
 	IncludeHealth         bool   `json:"health"`
 	IncludeIstioResources bool   `json:"istioResources"`
 }
 
-func (p *workloadParams) extract(r *http.Request) {
+func (p *workloadParams) extract(r *http.Request) error {
 	vars := mux.Vars(r)
 	query := r.URL.Query()
 	p.baseExtract(r, vars)
 	p.Namespace = vars["namespace"]
 	p.WorkloadName = vars["workload"]
-	p.WorkloadType = query.Get("type")
 	p.ClusterName = clusterNameFromQuery(query)
 
 	var err error
@@ -53,6 +55,12 @@ func (p *workloadParams) extract(r *http.Request) {
 	if err != nil {
 		p.IncludeIstioResources = true
 	}
+
+	p.WorkloadGVK, err = util.StringToGVK(query.Get("workloadGVK"))
+	if err != nil {
+		return err
+	}
+	return nil
 }
 
 // ClustersWorkloads is the API handler to fetch all the workloads to be displayed, related to a single namespace
@@ -60,7 +68,11 @@ func ClustersWorkloads(w http.ResponseWriter, r *http.Request) {
 	query := r.URL.Query()
 	namespacesQueryParam := query.Get("namespaces") // csl of namespaces
 	p := workloadParams{}
-	p.extract(r)
+	errParse := p.extract(r)
+	if errParse != nil {
+		RespondWithError(w, http.StatusInternalServerError, "Request parsing error: "+errParse.Error())
+		return
+	}
 
 	// Get business layer
 	businessLayer, err := getBusiness(r)
@@ -121,11 +133,15 @@ func ClustersWorkloads(w http.ResponseWriter, r *http.Request) {
 // WorkloadDetails is the API handler to fetch all details to be displayed, related to a single workload
 func WorkloadDetails(w http.ResponseWriter, r *http.Request) {
 	p := workloadParams{}
-	p.extract(r)
+	errParse := p.extract(r)
+	if errParse != nil {
+		RespondWithError(w, http.StatusInternalServerError, "Request parsing error: "+errParse.Error())
+		return
+	}
 
 	criteria := business.WorkloadCriteria{
 		Namespace: p.Namespace, WorkloadName: p.WorkloadName,
-		WorkloadType: p.WorkloadType, IncludeIstioResources: true, IncludeServices: true, IncludeHealth: p.IncludeHealth, RateInterval: p.RateInterval,
+		WorkloadGVK: p.WorkloadGVK, IncludeIstioResources: true, IncludeServices: true, IncludeHealth: p.IncludeHealth, RateInterval: p.RateInterval,
 		QueryTime: p.QueryTime, Cluster: p.ClusterName,
 	}
 
@@ -195,7 +211,11 @@ func WorkloadUpdate(w http.ResponseWriter, r *http.Request) {
 
 	namespace := params["namespace"]
 	workload := params["workload"]
-	workloadType := query.Get("type")
+	workloadGVK, errGVK := util.StringToGVK(query.Get("workloadGVK"))
+	if errGVK != nil {
+		RespondWithError(w, http.StatusBadRequest, "Update request with bad workloadGVK param: "+errGVK.Error())
+	}
+
 	cluster := clusterNameFromQuery(query)
 	log.Debugf("Cluster: %s", cluster)
 
@@ -222,7 +242,7 @@ func WorkloadUpdate(w http.ResponseWriter, r *http.Request) {
 		}()
 	}
 
-	workloadDetails, err := business.Workload.UpdateWorkload(r.Context(), cluster, namespace, workload, workloadType, true, jsonPatch, patchType)
+	workloadDetails, err := business.Workload.UpdateWorkload(r.Context(), cluster, namespace, workload, workloadGVK, true, jsonPatch, patchType)
 	if includeValidations && err == nil {
 		wg.Wait()
 		workloadDetails.Validations = istioConfigValidations
@@ -232,7 +252,7 @@ func WorkloadUpdate(w http.ResponseWriter, r *http.Request) {
 		handleErrorResponse(w, err)
 		return
 	}
-	auditMsg := fmt.Sprintf("UPDATE on Cluster: [%s] Namespace: [%s] Workload name: [%s] Type: [%s] Patch: [%s]", cluster, namespace, workload, workloadType, jsonPatch)
+	auditMsg := fmt.Sprintf("UPDATE on Cluster: [%s] Namespace: [%s] Workload name: [%s] Type: [%s] Patch: [%s]", cluster, namespace, workload, workloadGVK, jsonPatch)
 	audit(r, auditMsg)
 	RespondWithJSON(w, http.StatusOK, workloadDetails)
 }
diff --git a/kubernetes/filters.go b/kubernetes/filters.go
index 851e57c63..972c80a42 100644
--- a/kubernetes/filters.go
+++ b/kubernetes/filters.go
@@ -11,10 +11,12 @@ import (
 	"k8s.io/apimachinery/pkg/api/meta"
 	"k8s.io/apimachinery/pkg/labels"
 	"k8s.io/apimachinery/pkg/runtime"
+	"k8s.io/apimachinery/pkg/runtime/schema"
 	k8s_networking_v1 "sigs.k8s.io/gateway-api/apis/v1"
 	k8s_networking_v1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1"
 
 	"github.com/kiali/kiali/config"
+	"github.com/kiali/kiali/log"
 )
 
 func FilterAuthorizationPoliciesBySelector(workloadSelector string, authorizationpolicies []*security_v1.AuthorizationPolicy) []*security_v1.AuthorizationPolicy {
@@ -217,12 +219,16 @@ func FilterK8sGatewaysByRoutes(allGws []*k8s_networking_v1.Gateway, httpRoutes [
 	return gateways
 }
 
-func FilterPodsByController(controllerName string, controllerType string, allPods []core_v1.Pod) []core_v1.Pod {
+func FilterPodsByController(controllerName string, controllerGVK schema.GroupVersionKind, allPods []core_v1.Pod) []core_v1.Pod {
 	var pods []core_v1.Pod
 	for _, pod := range allPods {
 		for _, ref := range pod.OwnerReferences {
-			// TODO: Kind is not a definitive reference. Need to include check for API version as well.
-			if ref.Controller != nil && *ref.Controller && ref.Name == controllerName && ref.Kind == controllerType {
+			refGV, err := schema.ParseGroupVersion(ref.APIVersion)
+			if err != nil {
+				log.Errorf("could not parse OwnerReference api version %q: %v", ref.APIVersion, err)
+				continue
+			}
+			if ref.Controller != nil && *ref.Controller && ref.Name == controllerName && refGV.WithKind(ref.Kind) == controllerGVK {
 				pods = append(pods, pod)
 				break
 			}
diff --git a/kubernetes/kubernetes.go b/kubernetes/kubernetes.go
index a94950da0..dbb6c7b5e 100644
--- a/kubernetes/kubernetes.go
+++ b/kubernetes/kubernetes.go
@@ -57,7 +57,7 @@ type K8SClientInterface interface {
 	StreamPodLogs(namespace, name string, opts *core_v1.PodLogOptions) (io.ReadCloser, error)
 	UpdateNamespace(namespace string, jsonPatch string) (*core_v1.Namespace, error)
 	UpdateService(namespace string, name string, jsonPatch string, patchType string) error
-	UpdateWorkload(namespace string, name string, workloadType string, jsonPatch string, patchType string) error
+	UpdateWorkload(namespace string, name string, workloadGVK schema.GroupVersionKind, jsonPatch string, patchType string) error
 }
 
 type OSClientInterface interface {
@@ -456,34 +456,34 @@ func (in *K8SClient) GetSelfSubjectAccessReview(ctx context.Context, namespace,
 	return result, err
 }
 
-func (in *K8SClient) UpdateWorkload(namespace string, workloadName string, workloadType string, jsonPatch string, patchType string) error {
+func (in *K8SClient) UpdateWorkload(namespace string, workloadName string, workloadGVK schema.GroupVersionKind, jsonPatch string, patchType string) error {
 	emptyPatchOptions := meta_v1.PatchOptions{}
 	bytePatch := []byte(jsonPatch)
 	var err error
-	switch workloadType {
-	case DeploymentType:
+	switch workloadGVK {
+	case Deployments:
 		_, err = in.k8s.AppsV1().Deployments(namespace).Patch(in.ctx, workloadName, GetPatchType(patchType), bytePatch, emptyPatchOptions)
-	case ReplicaSetType:
+	case ReplicaSets:
 		_, err = in.k8s.AppsV1().ReplicaSets(namespace).Patch(in.ctx, workloadName, GetPatchType(patchType), bytePatch, emptyPatchOptions)
-	case ReplicationControllerType:
+	case ReplicationControllers:
 		_, err = in.k8s.CoreV1().ReplicationControllers(namespace).Patch(in.ctx, workloadName, GetPatchType(patchType), bytePatch, emptyPatchOptions)
-	case DeploymentConfigType:
+	case DeploymentConfigs:
 		if in.IsOpenShift() {
 			result := &osapps_v1.DeploymentConfigList{}
 			err = in.k8s.Discovery().RESTClient().Patch(GetPatchType(patchType)).Prefix("apis", "apps.openshift.io", "v1").Namespace(namespace).Resource("deploymentconfigs").SubResource(workloadName).Body(bytePatch).Do(in.ctx).Into(result)
 		}
-	case StatefulSetType:
+	case StatefulSets:
 		_, err = in.k8s.AppsV1().StatefulSets(namespace).Patch(in.ctx, workloadName, GetPatchType(patchType), bytePatch, emptyPatchOptions)
-	case JobType:
+	case Jobs:
 		_, err = in.k8s.BatchV1().Jobs(namespace).Patch(in.ctx, workloadName, GetPatchType(patchType), bytePatch, emptyPatchOptions)
-	case CronJobType:
+	case CronJobs:
 		_, err = in.k8s.BatchV1().CronJobs(namespace).Patch(in.ctx, workloadName, GetPatchType(patchType), bytePatch, emptyPatchOptions)
-	case PodType:
+	case Pods:
 		_, err = in.k8s.CoreV1().Pods(namespace).Patch(in.ctx, workloadName, GetPatchType(patchType), bytePatch, emptyPatchOptions)
-	case DaemonSetType:
+	case DaemonSets:
 		_, err = in.k8s.AppsV1().DaemonSets(namespace).Patch(in.ctx, workloadName, GetPatchType(patchType), bytePatch, emptyPatchOptions)
 	default:
-		err = fmt.Errorf("Workload type %s not found", workloadType)
+		err = fmt.Errorf("Workload type %s not found", workloadGVK.String())
 	}
 	return err
 }
diff --git a/models/dashboards.go b/models/dashboards.go
index bcf7beb1d..5a7deea0f 100644
--- a/models/dashboards.go
+++ b/models/dashboards.go
@@ -4,6 +4,8 @@ import (
 	"fmt"
 	"sort"
 
+	"k8s.io/apimachinery/pkg/runtime/schema"
+
 	"github.com/kiali/kiali/config"
 	"github.com/kiali/kiali/config/dashboards"
 	"github.com/kiali/kiali/prometheus"
@@ -17,7 +19,7 @@ type DashboardQuery struct {
 	AdditionalLabels  []Aggregation
 	RawDataAggregator string
 	Workload          string
-	WorkloadType      string
+	WorkloadGVK       schema.GroupVersionKind
 }
 
 // FillDefaults fills the struct with default parameters
diff --git a/models/istio_config.go b/models/istio_config.go
index e0c30d448..12c76e167 100644
--- a/models/istio_config.go
+++ b/models/istio_config.go
@@ -363,134 +363,134 @@ func (icd *IstioConfigDetails) UnmarshalJSON(data []byte) error {
 	icd.IstioConfigHelpFields = temp.IstioConfigHelpFields
 
 	// Based on the GVK, determine which resource type to unmarshal the resource into
-	switch temp.ObjectGVK.String() {
-	case kubernetes.AuthorizationPolicies.String():
+	switch temp.ObjectGVK {
+	case kubernetes.AuthorizationPolicies:
 		var ap security_v1.AuthorizationPolicy
 		if err := json.Unmarshal(temp.Resource, &ap); err != nil {
 			return err
 		}
 		icd.AuthorizationPolicy = &ap
 
-	case kubernetes.DestinationRules.String():
+	case kubernetes.DestinationRules:
 		var dr networking_v1.DestinationRule
 		if err := json.Unmarshal(temp.Resource, &dr); err != nil {
 			return err
 		}
 		icd.DestinationRule = &dr
 
-	case kubernetes.EnvoyFilters.String():
+	case kubernetes.EnvoyFilters:
 		var ef networking_v1alpha3.EnvoyFilter
 		if err := json.Unmarshal(temp.Resource, &ef); err != nil {
 			return err
 		}
 		icd.EnvoyFilter = &ef
 
-	case kubernetes.Gateways.String():
+	case kubernetes.Gateways:
 		var gw networking_v1.Gateway
 		if err := json.Unmarshal(temp.Resource, &gw); err != nil {
 			return err
 		}
 		icd.Gateway = &gw
 
-	case kubernetes.PeerAuthentications.String():
+	case kubernetes.PeerAuthentications:
 		var pa security_v1.PeerAuthentication
 		if err := json.Unmarshal(temp.Resource, &pa); err != nil {
 			return err
 		}
 		icd.PeerAuthentication = &pa
 
-	case kubernetes.RequestAuthentications.String():
+	case kubernetes.RequestAuthentications:
 		var ra security_v1.RequestAuthentication
 		if err := json.Unmarshal(temp.Resource, &ra); err != nil {
 			return err
 		}
 		icd.RequestAuthentication = &ra
 
-	case kubernetes.ServiceEntries.String():
+	case kubernetes.ServiceEntries:
 		var se networking_v1.ServiceEntry
 		if err := json.Unmarshal(temp.Resource, &se); err != nil {
 			return err
 		}
 		icd.ServiceEntry = &se
 
-	case kubernetes.Sidecars.String():
+	case kubernetes.Sidecars:
 		var sc networking_v1.Sidecar
 		if err := json.Unmarshal(temp.Resource, &sc); err != nil {
 			return err
 		}
 		icd.Sidecar = &sc
 
-	case kubernetes.VirtualServices.String():
+	case kubernetes.VirtualServices:
 		var vs networking_v1.VirtualService
 		if err := json.Unmarshal(temp.Resource, &vs); err != nil {
 			return err
 		}
 		icd.VirtualService = &vs
 
-	case kubernetes.WorkloadEntries.String():
+	case kubernetes.WorkloadEntries:
 		var we networking_v1.WorkloadEntry
 		if err := json.Unmarshal(temp.Resource, &we); err != nil {
 			return err
 		}
 		icd.WorkloadEntry = &we
 
-	case kubernetes.WorkloadGroups.String():
+	case kubernetes.WorkloadGroups:
 		var wg networking_v1.WorkloadGroup
 		if err := json.Unmarshal(temp.Resource, &wg); err != nil {
 			return err
 		}
 		icd.WorkloadGroup = &wg
 
-	case kubernetes.WasmPlugins.String():
+	case kubernetes.WasmPlugins:
 		var wp extentions_v1alpha1.WasmPlugin
 		if err := json.Unmarshal(temp.Resource, &wp); err != nil {
 			return err
 		}
 		icd.WasmPlugin = &wp
 
-	case kubernetes.Telemetries.String():
+	case kubernetes.Telemetries:
 		var tm telemetry_v1.Telemetry
 		if err := json.Unmarshal(temp.Resource, &tm); err != nil {
 			return err
 		}
 		icd.Telemetry = &tm
 
-	case kubernetes.K8sGateways.String():
+	case kubernetes.K8sGateways:
 		var kg k8s_networking_v1.Gateway
 		if err := json.Unmarshal(temp.Resource, &kg); err != nil {
 			return err
 		}
 		icd.K8sGateway = &kg
 
-	case kubernetes.K8sGRPCRoutes.String():
+	case kubernetes.K8sGRPCRoutes:
 		var grpcRoute k8s_networking_v1.GRPCRoute
 		if err := json.Unmarshal(temp.Resource, &grpcRoute); err != nil {
 			return err
 		}
 		icd.K8sGRPCRoute = &grpcRoute
 
-	case kubernetes.K8sHTTPRoutes.String():
+	case kubernetes.K8sHTTPRoutes:
 		var httpRoute k8s_networking_v1.HTTPRoute
 		if err := json.Unmarshal(temp.Resource, &httpRoute); err != nil {
 			return err
 		}
 		icd.K8sHTTPRoute = &httpRoute
 
-	case kubernetes.K8sReferenceGrants.String():
+	case kubernetes.K8sReferenceGrants:
 		var refGrant k8s_networking_v1beta1.ReferenceGrant
 		if err := json.Unmarshal(temp.Resource, &refGrant); err != nil {
 			return err
 		}
 		icd.K8sReferenceGrant = &refGrant
 
-	case kubernetes.K8sTCPRoutes.String():
+	case kubernetes.K8sTCPRoutes:
 		var tcpRoute k8s_networking_v1alpha2.TCPRoute
 		if err := json.Unmarshal(temp.Resource, &tcpRoute); err != nil {
 			return err
 		}
 		icd.K8sTCPRoute = &tcpRoute
 
-	case kubernetes.K8sTLSRoutes.String():
+	case kubernetes.K8sTLSRoutes:
 		var tlsRoute k8s_networking_v1alpha2.TLSRoute
 		if err := json.Unmarshal(temp.Resource, &tlsRoute); err != nil {
 			return err
diff --git a/models/istio_validation.go b/models/istio_validation.go
index 381f35fe2..34abf41e5 100644
--- a/models/istio_validation.go
+++ b/models/istio_validation.go
@@ -381,7 +381,7 @@ func (iv IstioValidations) FilterBySingleType(objectGVK schema.GroupVersionKind,
 	fiv := IstioValidations{}
 	for k, v := range iv {
 		// We don't want to filter other types
-		if k.ObjectGVK.String() != objectGVK.String() {
+		if k.ObjectGVK != objectGVK {
 			fiv[k] = v
 		} else {
 			// But for this exact type we're strict
@@ -397,7 +397,7 @@ func (iv IstioValidations) FilterBySingleType(objectGVK schema.GroupVersionKind,
 func (iv IstioValidations) FilterByKey(objectGVK schema.GroupVersionKind, name string) IstioValidations {
 	fiv := IstioValidations{}
 	for k, v := range iv {
-		if k.Name == name && k.ObjectGVK.String() == objectGVK.String() {
+		if k.Name == name && k.ObjectGVK == objectGVK {
 			fiv[k] = v
 		}
 	}
diff --git a/models/workload.go b/models/workload.go
index 91544ad03..a399037a6 100644
--- a/models/workload.go
+++ b/models/workload.go
@@ -10,8 +10,10 @@ import (
 	core_v1 "k8s.io/api/core/v1"
 	meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/labels"
+	"k8s.io/apimachinery/pkg/runtime/schema"
 
 	"github.com/kiali/kiali/config"
+	"github.com/kiali/kiali/kubernetes"
 )
 
 type ClusterWorkloads struct {
@@ -67,10 +69,10 @@ type WorkloadListItem struct {
 	// The kube cluster where this workload is located.
 	Cluster string `json:"cluster"`
 
-	// Type of the workload
+	// Group Version Kind of the workload
 	// required: true
-	// example: deployment
-	Type string `json:"type"`
+	// example: 'apps/v1, Kind=Deployment'
+	WorkloadGVK schema.GroupVersionKind `json:"gvk"`
 
 	// Creation timestamp (in RFC3339 format)
 	// required: true
@@ -207,7 +209,7 @@ func (workload *WorkloadListItem) ParseWorkload(w *Workload) {
 	conf := config.Get()
 	workload.Name = w.Name
 	workload.Namespace = w.Namespace
-	workload.Type = w.Type
+	workload.WorkloadGVK = w.WorkloadGVK
 	workload.CreatedAt = w.CreatedAt
 	workload.ResourceVersion = w.ResourceVersion
 	workload.IstioSidecar = w.HasIstioSidecar()
@@ -284,7 +286,7 @@ func (workload *Workload) parseObjectMeta(meta *meta_v1.ObjectMeta, tplMeta *met
 }
 
 func (workload *Workload) ParseDeployment(d *apps_v1.Deployment) {
-	workload.Type = "Deployment"
+	workload.WorkloadGVK = kubernetes.Deployments
 	workload.parseObjectMeta(&d.ObjectMeta, &d.Spec.Template.ObjectMeta)
 	if d.Spec.Replicas != nil {
 		workload.DesiredReplicas = *d.Spec.Replicas
@@ -299,7 +301,7 @@ func (workload *Workload) ParseDeployment(d *apps_v1.Deployment) {
 }
 
 func (workload *Workload) ParseReplicaSet(r *apps_v1.ReplicaSet) {
-	workload.Type = "ReplicaSet"
+	workload.WorkloadGVK = kubernetes.ReplicaSets
 	workload.parseObjectMeta(&r.ObjectMeta, &r.Spec.Template.ObjectMeta)
 	if r.Spec.Replicas != nil {
 		workload.DesiredReplicas = *r.Spec.Replicas
@@ -308,12 +310,12 @@ func (workload *Workload) ParseReplicaSet(r *apps_v1.ReplicaSet) {
 	workload.AvailableReplicas = r.Status.AvailableReplicas
 }
 
-func (workload *Workload) ParseReplicaSetParent(r *apps_v1.ReplicaSet, workloadName string, workloadType string) {
+func (workload *Workload) ParseReplicaSetParent(r *apps_v1.ReplicaSet, workloadName string, workloadGVK schema.GroupVersionKind) {
 	// Some properties are taken from the ReplicaSet
 	workload.parseObjectMeta(&r.ObjectMeta, &r.Spec.Template.ObjectMeta)
 	// But name and type are coming from the parent
 	// Custom properties from parent controller are not processed by Kiali
-	workload.Type = workloadType
+	workload.WorkloadGVK = workloadGVK
 	workload.Name = workloadName
 	if r.Spec.Replicas != nil {
 		workload.DesiredReplicas = *r.Spec.Replicas
@@ -323,7 +325,7 @@ func (workload *Workload) ParseReplicaSetParent(r *apps_v1.ReplicaSet, workloadN
 }
 
 func (workload *Workload) ParseReplicationController(r *core_v1.ReplicationController) {
-	workload.Type = "ReplicationController"
+	workload.WorkloadGVK = kubernetes.ReplicationControllers
 	workload.parseObjectMeta(&r.ObjectMeta, &r.Spec.Template.ObjectMeta)
 	if r.Spec.Replicas != nil {
 		workload.DesiredReplicas = *r.Spec.Replicas
@@ -333,7 +335,7 @@ func (workload *Workload) ParseReplicationController(r *core_v1.ReplicationContr
 }
 
 func (workload *Workload) ParseDeploymentConfig(dc *osapps_v1.DeploymentConfig) {
-	workload.Type = "DeploymentConfig"
+	workload.WorkloadGVK = kubernetes.DeploymentConfigs
 	workload.parseObjectMeta(&dc.ObjectMeta, &dc.Spec.Template.ObjectMeta)
 	workload.DesiredReplicas = dc.Spec.Replicas
 	workload.CurrentReplicas = dc.Status.Replicas
@@ -341,7 +343,7 @@ func (workload *Workload) ParseDeploymentConfig(dc *osapps_v1.DeploymentConfig)
 }
 
 func (workload *Workload) ParseStatefulSet(s *apps_v1.StatefulSet) {
-	workload.Type = "StatefulSet"
+	workload.WorkloadGVK = kubernetes.StatefulSets
 	workload.parseObjectMeta(&s.ObjectMeta, &s.Spec.Template.ObjectMeta)
 	if s.Spec.Replicas != nil {
 		workload.DesiredReplicas = *s.Spec.Replicas
@@ -351,7 +353,7 @@ func (workload *Workload) ParseStatefulSet(s *apps_v1.StatefulSet) {
 }
 
 func (workload *Workload) ParsePod(pod *core_v1.Pod) {
-	workload.Type = "Pod"
+	workload.WorkloadGVK = kubernetes.Pods
 	workload.parseObjectMeta(&pod.ObjectMeta, &pod.ObjectMeta)
 
 	var podReplicas, podAvailableReplicas int32
@@ -375,7 +377,7 @@ func (workload *Workload) ParsePod(pod *core_v1.Pod) {
 }
 
 func (workload *Workload) ParseJob(job *batch_v1.Job) {
-	workload.Type = "Job"
+	workload.WorkloadGVK = kubernetes.Jobs
 	workload.parseObjectMeta(&job.ObjectMeta, &job.ObjectMeta)
 	// Job controller does not use replica parameters as other controllers
 	// this is a workaround to use same values from Workload perspective
@@ -385,7 +387,7 @@ func (workload *Workload) ParseJob(job *batch_v1.Job) {
 }
 
 func (workload *Workload) ParseCronJob(cnjb *batch_v1.CronJob) {
-	workload.Type = "CronJob"
+	workload.WorkloadGVK = kubernetes.CronJobs
 	workload.parseObjectMeta(&cnjb.ObjectMeta, &cnjb.ObjectMeta)
 
 	// We don't have the information of this controller
@@ -410,7 +412,7 @@ func (workload *Workload) ParseCronJob(cnjb *batch_v1.CronJob) {
 }
 
 func (workload *Workload) ParseDaemonSet(ds *apps_v1.DaemonSet) {
-	workload.Type = "DaemonSet"
+	workload.WorkloadGVK = kubernetes.DaemonSets
 	workload.parseObjectMeta(&ds.ObjectMeta, &ds.Spec.Template.ObjectMeta)
 	// This is a cornercase for DaemonSet controllers
 	// Desired is the number of desired nodes in a cluster that are running a DaemonSet Pod
@@ -421,10 +423,10 @@ func (workload *Workload) ParseDaemonSet(ds *apps_v1.DaemonSet) {
 	workload.HealthAnnotations = GetHealthAnnotation(ds.Annotations, GetHealthConfigAnnotation())
 }
 
-func (workload *Workload) ParsePods(controllerName string, controllerType string, pods []core_v1.Pod) {
+func (workload *Workload) ParsePods(controllerName string, controllerGVK schema.GroupVersionKind, pods []core_v1.Pod) {
 	conf := config.Get()
 	workload.Name = controllerName
-	workload.Type = controllerType
+	workload.WorkloadGVK = controllerGVK
 	// We don't have the information of this controller
 	// We will infer the number of replicas as the number of pods without succeed state
 	// We will infer the number of available as the number of pods with running state
@@ -476,7 +478,7 @@ func (workload *Workload) HasIstioSidecar() bool {
 		return true
 	}
 	// All pods in a deployment should be the same
-	if workload.Type == "Deployment" {
+	if workload.WorkloadGVK == kubernetes.Deployments {
 		return workload.Pods[0].HasIstioSidecar()
 	}
 	// Need to check each pod
@@ -545,7 +547,7 @@ func (workload *Workload) HasIstioAmbient() bool {
 		return false
 	}
 	// All pods in a deployment should be the same
-	if workload.Type == "Deployment" {
+	if workload.WorkloadGVK == kubernetes.Deployments {
 		return workload.Pods[0].AmbientEnabled()
 	}
 	// Need to check each pod


Test patch:
diff --git a/business/test_util.go b/business/test_util.go
index 87278c398..cba06a570 100644
--- a/business/test_util.go
+++ b/business/test_util.go
@@ -26,7 +26,8 @@ func FakeDeployments(conf config.Config) []apps_v1.Deployment {
 	return []apps_v1.Deployment{
 		{
 			TypeMeta: meta_v1.TypeMeta{
-				Kind: "Deployment",
+				APIVersion: kubernetes.Deployments.GroupVersion().String(),
+				Kind:       kubernetes.Deployments.Kind,
 			},
 			ObjectMeta: meta_v1.ObjectMeta{
 				Name:              "httpbin-v1",
@@ -48,7 +49,8 @@ func FakeDeployments(conf config.Config) []apps_v1.Deployment {
 		},
 		{
 			TypeMeta: meta_v1.TypeMeta{
-				Kind: "Deployment",
+				APIVersion: kubernetes.Deployments.GroupVersion().String(),
+				Kind:       kubernetes.Deployments.Kind,
 			},
 			ObjectMeta: meta_v1.ObjectMeta{
 				Name:              "httpbin-v2",
@@ -70,7 +72,8 @@ func FakeDeployments(conf config.Config) []apps_v1.Deployment {
 		},
 		{
 			TypeMeta: meta_v1.TypeMeta{
-				Kind: "Deployment",
+				APIVersion: kubernetes.Deployments.GroupVersion().String(),
+				Kind:       kubernetes.Deployments.Kind,
 			},
 			ObjectMeta: meta_v1.ObjectMeta{
 				Name:              "httpbin-v3",
@@ -102,7 +105,8 @@ func FakeDuplicatedDeployments() []apps_v1.Deployment {
 	return []apps_v1.Deployment{
 		{
 			TypeMeta: meta_v1.TypeMeta{
-				Kind: "Deployment",
+				APIVersion: kubernetes.Deployments.GroupVersion().String(),
+				Kind:       kubernetes.Deployments.Kind,
 			},
 			ObjectMeta: meta_v1.ObjectMeta{
 				Name:              "duplicated-v1",
@@ -131,7 +135,8 @@ func FakeReplicaSets(conf config.Config) []apps_v1.ReplicaSet {
 	return []apps_v1.ReplicaSet{
 		{
 			TypeMeta: meta_v1.TypeMeta{
-				Kind: "ReplicaSet",
+				APIVersion: kubernetes.ReplicaSets.GroupVersion().String(),
+				Kind:       kubernetes.ReplicaSets.Kind,
 			},
 			ObjectMeta: meta_v1.ObjectMeta{
 				Name:              "httpbin-v1",
@@ -153,7 +158,8 @@ func FakeReplicaSets(conf config.Config) []apps_v1.ReplicaSet {
 		},
 		{
 			TypeMeta: meta_v1.TypeMeta{
-				Kind: "ReplicaSet",
+				APIVersion: kubernetes.ReplicaSets.GroupVersion().String(),
+				Kind:       kubernetes.ReplicaSets.Kind,
 			},
 			ObjectMeta: meta_v1.ObjectMeta{
 				Name:              "httpbin-v2",
@@ -175,7 +181,8 @@ func FakeReplicaSets(conf config.Config) []apps_v1.ReplicaSet {
 		},
 		{
 			TypeMeta: meta_v1.TypeMeta{
-				Kind: "ReplicaSet",
+				APIVersion: kubernetes.ReplicaSets.GroupVersion().String(),
+				Kind:       kubernetes.ReplicaSets.Kind,
 			},
 			ObjectMeta: meta_v1.ObjectMeta{
 				Name:              "httpbin-v3",
@@ -208,7 +215,8 @@ func FakeDuplicatedReplicaSets() []apps_v1.ReplicaSet {
 	return []apps_v1.ReplicaSet{
 		{
 			TypeMeta: meta_v1.TypeMeta{
-				Kind: "ReplicaSet",
+				APIVersion: kubernetes.ReplicaSets.GroupVersion().String(),
+				Kind:       kubernetes.ReplicaSets.Kind,
 			},
 			ObjectMeta: meta_v1.ObjectMeta{
 				Name: "duplicated-v1-12345",
@@ -216,7 +224,8 @@ func FakeDuplicatedReplicaSets() []apps_v1.ReplicaSet {
 				CreationTimestamp: meta_v1.NewTime(t1),
 				OwnerReferences: []meta_v1.OwnerReference{{
 					Controller: &controller,
-					Kind:       "Deployment",
+					APIVersion: kubernetes.Deployments.GroupVersion().String(),
+					Kind:       kubernetes.Deployments.Kind,
 					Name:       "duplicated-v1",
 				}},
 			},
@@ -247,7 +256,8 @@ func FakeReplicationControllers() []core_v1.ReplicationController {
 	return []core_v1.ReplicationController{
 		{
 			TypeMeta: meta_v1.TypeMeta{
-				Kind: "ReplicationController",
+				APIVersion: kubernetes.ReplicationControllers.GroupVersion().String(),
+				Kind:       kubernetes.ReplicationControllers.Kind,
 			},
 			ObjectMeta: meta_v1.ObjectMeta{
 				Name:              "httpbin-v1",
@@ -269,7 +279,8 @@ func FakeReplicationControllers() []core_v1.ReplicationController {
 		},
 		{
 			TypeMeta: meta_v1.TypeMeta{
-				Kind: "ReplicationController",
+				APIVersion: kubernetes.ReplicationControllers.GroupVersion().String(),
+				Kind:       kubernetes.ReplicationControllers.Kind,
 			},
 			ObjectMeta: meta_v1.ObjectMeta{
 				Name:              "httpbin-v2",
@@ -291,7 +302,8 @@ func FakeReplicationControllers() []core_v1.ReplicationController {
 		},
 		{
 			TypeMeta: meta_v1.TypeMeta{
-				Kind: "ReplicationController",
+				APIVersion: kubernetes.ReplicationControllers.GroupVersion().String(),
+				Kind:       kubernetes.ReplicationControllers.Kind,
 			},
 			ObjectMeta: meta_v1.ObjectMeta{
 				Name:              "httpbin-v3",
@@ -324,7 +336,8 @@ func FakeDeploymentConfigs() []osapps_v1.DeploymentConfig {
 	return []osapps_v1.DeploymentConfig{
 		{
 			TypeMeta: meta_v1.TypeMeta{
-				Kind: "DeploymentConfig",
+				APIVersion: kubernetes.DeploymentConfigs.GroupVersion().String(),
+				Kind:       kubernetes.DeploymentConfigs.Kind,
 			},
 			ObjectMeta: meta_v1.ObjectMeta{
 				Name:              "httpbin-v1",
@@ -346,7 +359,8 @@ func FakeDeploymentConfigs() []osapps_v1.DeploymentConfig {
 		},
 		{
 			TypeMeta: meta_v1.TypeMeta{
-				Kind: "DeploymentConfig",
+				APIVersion: kubernetes.DeploymentConfigs.GroupVersion().String(),
+				Kind:       kubernetes.DeploymentConfigs.Kind,
 			},
 			ObjectMeta: meta_v1.ObjectMeta{
 				Name:              "httpbin-v2",
@@ -368,7 +382,8 @@ func FakeDeploymentConfigs() []osapps_v1.DeploymentConfig {
 		},
 		{
 			TypeMeta: meta_v1.TypeMeta{
-				Kind: "DeploymentConfig",
+				APIVersion: kubernetes.DeploymentConfigs.GroupVersion().String(),
+				Kind:       kubernetes.DeploymentConfigs.Kind,
 			},
 			ObjectMeta: meta_v1.ObjectMeta{
 				Name:              "httpbin-v3",
@@ -401,7 +416,8 @@ func FakeStatefulSets() []apps_v1.StatefulSet {
 	return []apps_v1.StatefulSet{
 		{
 			TypeMeta: meta_v1.TypeMeta{
-				Kind: "StatefulSet",
+				APIVersion: kubernetes.StatefulSets.GroupVersion().String(),
+				Kind:       kubernetes.StatefulSets.Kind,
 			},
 			ObjectMeta: meta_v1.ObjectMeta{
 				Name:              "httpbin-v1",
@@ -422,7 +438,8 @@ func FakeStatefulSets() []apps_v1.StatefulSet {
 		},
 		{
 			TypeMeta: meta_v1.TypeMeta{
-				Kind: "StatefulSet",
+				APIVersion: kubernetes.StatefulSets.GroupVersion().String(),
+				Kind:       kubernetes.StatefulSets.Kind,
 			},
 			ObjectMeta: meta_v1.ObjectMeta{
 				Name:              "httpbin-v2",
@@ -443,7 +460,8 @@ func FakeStatefulSets() []apps_v1.StatefulSet {
 		},
 		{
 			TypeMeta: meta_v1.TypeMeta{
-				Kind: "StatefulSet",
+				APIVersion: kubernetes.StatefulSets.GroupVersion().String(),
+				Kind:       kubernetes.StatefulSets.Kind,
 			},
 			ObjectMeta: meta_v1.ObjectMeta{
 				Name:              "httpbin-v3",
@@ -475,7 +493,8 @@ func FakeDaemonSets() []apps_v1.DaemonSet {
 	return []apps_v1.DaemonSet{
 		{
 			TypeMeta: meta_v1.TypeMeta{
-				Kind: "DaemonSet",
+				APIVersion: kubernetes.DaemonSets.GroupVersion().String(),
+				Kind:       kubernetes.DaemonSets.Kind,
 			},
 			ObjectMeta: meta_v1.ObjectMeta{
 				Name:              "httpbin-v1",
@@ -497,7 +516,8 @@ func FakeDaemonSets() []apps_v1.DaemonSet {
 		},
 		{
 			TypeMeta: meta_v1.TypeMeta{
-				Kind: "DaemonSet",
+				APIVersion: kubernetes.DaemonSets.GroupVersion().String(),
+				Kind:       kubernetes.DaemonSets.Kind,
 			},
 			ObjectMeta: meta_v1.ObjectMeta{
 				Name:              "httpbin-v2",
@@ -519,7 +539,8 @@ func FakeDaemonSets() []apps_v1.DaemonSet {
 		},
 		{
 			TypeMeta: meta_v1.TypeMeta{
-				Kind: "DaemonSet",
+				APIVersion: kubernetes.DaemonSets.GroupVersion().String(),
+				Kind:       kubernetes.DaemonSets.Kind,
 			},
 			ObjectMeta: meta_v1.ObjectMeta{
 				Name:              "httpbin-v3",
@@ -551,7 +572,8 @@ func FakeDuplicatedStatefulSets() []apps_v1.StatefulSet {
 	return []apps_v1.StatefulSet{
 		{
 			TypeMeta: meta_v1.TypeMeta{
-				Kind: "StatefulSet",
+				APIVersion: kubernetes.StatefulSets.GroupVersion().String(),
+				Kind:       kubernetes.StatefulSets.Kind,
 			},
 			ObjectMeta: meta_v1.ObjectMeta{
 				Name:              "duplicated-v1",
@@ -582,7 +604,8 @@ func FakeDepSyncedWithRS() []apps_v1.Deployment {
 	return []apps_v1.Deployment{
 		{
 			TypeMeta: meta_v1.TypeMeta{
-				Kind: "Deployment",
+				APIVersion: kubernetes.Deployments.GroupVersion().String(),
+				Kind:       kubernetes.Deployments.Kind,
 			},
 			ObjectMeta: meta_v1.ObjectMeta{
 				Name:              "details-v1",
@@ -615,7 +638,8 @@ func FakeRSSyncedWithPods() []apps_v1.ReplicaSet {
 	return []apps_v1.ReplicaSet{
 		{
 			TypeMeta: meta_v1.TypeMeta{
-				Kind: "ReplicaSet",
+				APIVersion: kubernetes.ReplicaSets.GroupVersion().String(),
+				Kind:       kubernetes.ReplicaSets.Kind,
 			},
 			ObjectMeta: meta_v1.ObjectMeta{
 				Name:              "details-v1-3618568057",
@@ -623,7 +647,8 @@ func FakeRSSyncedWithPods() []apps_v1.ReplicaSet {
 				CreationTimestamp: meta_v1.NewTime(t1),
 				OwnerReferences: []meta_v1.OwnerReference{{
 					Controller: &controller,
-					Kind:       "Deployment",
+					APIVersion: kubernetes.Deployments.GroupVersion().String(),
+					Kind:       kubernetes.Deployments.Kind,
 					Name:       "details-v1",
 				}},
 			},
@@ -659,7 +684,8 @@ func FakePodsSyncedWithDeployments() []core_v1.Pod {
 				Labels:            map[string]string{appLabel: "httpbin", versionLabel: "v1"},
 				OwnerReferences: []meta_v1.OwnerReference{{
 					Controller: &controller,
-					Kind:       "ReplicaSet",
+					APIVersion: kubernetes.ReplicaSets.GroupVersion().String(),
+					Kind:       kubernetes.ReplicaSets.Kind,
 					Name:       "details-v1-3618568057",
 				}},
 				Annotations: kubetest.FakeIstioAnnotations(),
@@ -693,7 +719,8 @@ func FakePodSyncedWithDeployments() *core_v1.Pod {
 			Labels:            map[string]string{appLabel: "httpbin", versionLabel: "v1"},
 			OwnerReferences: []meta_v1.OwnerReference{{
 				Controller: &controller,
-				Kind:       "ReplicaSet",
+				APIVersion: kubernetes.ReplicaSets.GroupVersion().String(),
+				Kind:       kubernetes.ReplicaSets.Kind,
 				Name:       "details-v1-3618568057",
 			}},
 			Annotations: kubetest.FakeIstioAnnotations(),
@@ -752,7 +779,8 @@ func FakePodsSyncedWithDuplicated() []core_v1.Pod {
 				Labels:            map[string]string{appLabel: "duplicated", versionLabel: "v1"},
 				OwnerReferences: []meta_v1.OwnerReference{{
 					Controller: &controller,
-					Kind:       "StatefulSet",
+					APIVersion: kubernetes.StatefulSets.GroupVersion().String(),
+					Kind:       kubernetes.StatefulSets.Kind,
 					Name:       "duplicated-v1",
 				}},
 				Annotations: kubetest.FakeIstioAnnotations(),
@@ -776,7 +804,8 @@ func FakePodsSyncedWithDuplicated() []core_v1.Pod {
 				Labels:            map[string]string{appLabel: "duplicated", versionLabel: "v1"},
 				OwnerReferences: []meta_v1.OwnerReference{{
 					Controller: &controller,
-					Kind:       "StatefulSet",
+					APIVersion: kubernetes.StatefulSets.GroupVersion().String(),
+					Kind:       kubernetes.StatefulSets.Kind,
 					Name:       "duplicated-v1",
 				}},
 				Annotations: kubetest.FakeIstioAnnotations(),
@@ -805,7 +834,8 @@ func FakePodsNoController() []core_v1.Pod {
 	return []core_v1.Pod{
 		{
 			TypeMeta: meta_v1.TypeMeta{
-				Kind: "Pod",
+				APIVersion: kubernetes.Pods.GroupVersion().String(),
+				Kind:       kubernetes.Pods.Kind,
 			},
 			ObjectMeta: meta_v1.ObjectMeta{
 				Name:              "orphan-pod",
@@ -844,7 +874,8 @@ func FakePodsFromCustomController() []core_v1.Pod {
 				Labels:            map[string]string{appLabel: "httpbin", versionLabel: "v1"},
 				OwnerReferences: []meta_v1.OwnerReference{{
 					Controller: &controller,
-					Kind:       "ReplicaSet",
+					APIVersion: kubernetes.ReplicaSets.GroupVersion().String(),
+					Kind:       kubernetes.ReplicaSets.Kind,
 					Name:       "custom-controller-RS-123",
 				}},
 				Annotations: kubetest.FakeIstioAnnotations(),
@@ -879,7 +910,8 @@ func FakeZtunnelPods() []core_v1.Pod {
 				Labels:            map[string]string{appLabel: "ztunnel", versionLabel: "v1"},
 				OwnerReferences: []meta_v1.OwnerReference{{
 					Controller: &controller,
-					Kind:       "ReplicaSet",
+					APIVersion: kubernetes.ReplicaSets.GroupVersion().String(),
+					Kind:       kubernetes.ReplicaSets.Kind,
 					Name:       "ztunnel",
 				}},
 				Annotations: kubetest.FakeIstioAnnotations(),
@@ -996,7 +1028,8 @@ func FakeZtunnelDaemonSet() []apps_v1.DaemonSet {
 	return []apps_v1.DaemonSet{
 		{
 			TypeMeta: meta_v1.TypeMeta{
-				Kind: "DaemonSet",
+				APIVersion: kubernetes.DaemonSets.GroupVersion().String(),
+				Kind:       kubernetes.DaemonSets.Kind,
 			},
 			ObjectMeta: meta_v1.ObjectMeta{
 				Name:              "ztunnel",
@@ -1032,7 +1065,8 @@ func FakeCustomControllerRSSyncedWithPods() []apps_v1.ReplicaSet {
 	return []apps_v1.ReplicaSet{
 		{
 			TypeMeta: meta_v1.TypeMeta{
-				Kind: "ReplicaSet",
+				APIVersion: kubernetes.ReplicaSets.GroupVersion().String(),
+				Kind:       kubernetes.ReplicaSets.Kind,
 			},
 			ObjectMeta: meta_v1.ObjectMeta{
 				Name:              "custom-controller-RS-123",
diff --git a/business/workloads_test.go b/business/workloads_test.go
index d2103111d..48135260e 100644
--- a/business/workloads_test.go
+++ b/business/workloads_test.go
@@ -81,15 +81,15 @@ func TestGetWorkloadListFromDeployments(t *testing.T) {
 	assert.Equal("httpbin-v1", workloads[0].Name)
 	assert.Equal(true, workloads[0].AppLabel)
 	assert.Equal(false, workloads[0].VersionLabel)
-	assert.Equal("Deployment", workloads[0].Type)
+	assert.Equal("Deployment", workloads[0].WorkloadGVK.Kind)
 	assert.Equal("httpbin-v2", workloads[1].Name)
 	assert.Equal(true, workloads[1].AppLabel)
 	assert.Equal(true, workloads[1].VersionLabel)
-	assert.Equal("Deployment", workloads[1].Type)
+	assert.Equal("Deployment", workloads[1].WorkloadGVK.Kind)
 	assert.Equal("httpbin-v3", workloads[2].Name)
 	assert.Equal(false, workloads[2].AppLabel)
 	assert.Equal(false, workloads[2].VersionLabel)
-	assert.Equal("Deployment", workloads[2].Type)
+	assert.Equal("Deployment", workloads[2].WorkloadGVK.Kind)
 }
 
 func TestGetWorkloadListFromReplicaSets(t *testing.T) {
@@ -122,15 +122,15 @@ func TestGetWorkloadListFromReplicaSets(t *testing.T) {
 	assert.Equal("httpbin-v1", workloads[0].Name)
 	assert.Equal(true, workloads[0].AppLabel)
 	assert.Equal(false, workloads[0].VersionLabel)
-	assert.Equal("ReplicaSet", workloads[0].Type)
+	assert.Equal("ReplicaSet", workloads[0].WorkloadGVK.Kind)
 	assert.Equal("httpbin-v2", workloads[1].Name)
 	assert.Equal(true, workloads[1].AppLabel)
 	assert.Equal(true, workloads[1].VersionLabel)
-	assert.Equal("ReplicaSet", workloads[1].Type)
+	assert.Equal("ReplicaSet", workloads[1].WorkloadGVK.Kind)
 	assert.Equal("httpbin-v3", workloads[2].Name)
 	assert.Equal(false, workloads[2].AppLabel)
 	assert.Equal(false, workloads[2].VersionLabel)
-	assert.Equal("ReplicaSet", workloads[2].Type)
+	assert.Equal("ReplicaSet", workloads[2].WorkloadGVK.Kind)
 }
 
 func TestGetWorkloadListFromReplicationControllers(t *testing.T) {
@@ -161,15 +161,15 @@ func TestGetWorkloadListFromReplicationControllers(t *testing.T) {
 	assert.Equal("httpbin-v1", workloads[0].Name)
 	assert.Equal(true, workloads[0].AppLabel)
 	assert.Equal(false, workloads[0].VersionLabel)
-	assert.Equal("ReplicationController", workloads[0].Type)
+	assert.Equal("ReplicationController", workloads[0].WorkloadGVK.Kind)
 	assert.Equal("httpbin-v2", workloads[1].Name)
 	assert.Equal(true, workloads[1].AppLabel)
 	assert.Equal(true, workloads[1].VersionLabel)
-	assert.Equal("ReplicationController", workloads[1].Type)
+	assert.Equal("ReplicationController", workloads[1].WorkloadGVK.Kind)
 	assert.Equal("httpbin-v3", workloads[2].Name)
 	assert.Equal(false, workloads[2].AppLabel)
 	assert.Equal(false, workloads[2].VersionLabel)
-	assert.Equal("ReplicationController", workloads[2].Type)
+	assert.Equal("ReplicationController", workloads[2].WorkloadGVK.Kind)
 }
 
 func TestGetWorkloadListFromDeploymentConfigs(t *testing.T) {
@@ -200,15 +200,15 @@ func TestGetWorkloadListFromDeploymentConfigs(t *testing.T) {
 	assert.Equal("httpbin-v1", workloads[0].Name)
 	assert.Equal(true, workloads[0].AppLabel)
 	assert.Equal(false, workloads[0].VersionLabel)
-	assert.Equal("DeploymentConfig", workloads[0].Type)
+	assert.Equal("DeploymentConfig", workloads[0].WorkloadGVK.Kind)
 	assert.Equal("httpbin-v2", workloads[1].Name)
 	assert.Equal(true, workloads[1].AppLabel)
 	assert.Equal(true, workloads[1].VersionLabel)
-	assert.Equal("DeploymentConfig", workloads[1].Type)
+	assert.Equal("DeploymentConfig", workloads[1].WorkloadGVK.Kind)
 	assert.Equal("httpbin-v3", workloads[2].Name)
 	assert.Equal(false, workloads[2].AppLabel)
 	assert.Equal(false, workloads[2].VersionLabel)
-	assert.Equal("DeploymentConfig", workloads[2].Type)
+	assert.Equal("DeploymentConfig", workloads[2].WorkloadGVK.Kind)
 }
 
 func TestGetWorkloadListFromStatefulSets(t *testing.T) {
@@ -239,15 +239,15 @@ func TestGetWorkloadListFromStatefulSets(t *testing.T) {
 	assert.Equal("httpbin-v1", workloads[0].Name)
 	assert.Equal(true, workloads[0].AppLabel)
 	assert.Equal(false, workloads[0].VersionLabel)
-	assert.Equal("StatefulSet", workloads[0].Type)
+	assert.Equal("StatefulSet", workloads[0].WorkloadGVK.Kind)
 	assert.Equal("httpbin-v2", workloads[1].Name)
 	assert.Equal(true, workloads[1].AppLabel)
 	assert.Equal(true, workloads[1].VersionLabel)
-	assert.Equal("StatefulSet", workloads[1].Type)
+	assert.Equal("StatefulSet", workloads[1].WorkloadGVK.Kind)
 	assert.Equal("httpbin-v3", workloads[2].Name)
 	assert.Equal(false, workloads[2].AppLabel)
 	assert.Equal(false, workloads[2].VersionLabel)
-	assert.Equal("StatefulSet", workloads[2].Type)
+	assert.Equal("StatefulSet", workloads[2].WorkloadGVK.Kind)
 }
 
 func TestGetWorkloadListFromDaemonSets(t *testing.T) {
@@ -278,15 +278,15 @@ func TestGetWorkloadListFromDaemonSets(t *testing.T) {
 	assert.Equal("httpbin-v1", workloads[0].Name)
 	assert.Equal(true, workloads[0].AppLabel)
 	assert.Equal(false, workloads[0].VersionLabel)
-	assert.Equal("DaemonSet", workloads[0].Type)
+	assert.Equal("DaemonSet", workloads[0].WorkloadGVK.Kind)
 	assert.Equal("httpbin-v2", workloads[1].Name)
 	assert.Equal(true, workloads[1].AppLabel)
 	assert.Equal(true, workloads[1].VersionLabel)
-	assert.Equal("DaemonSet", workloads[1].Type)
+	assert.Equal("DaemonSet", workloads[1].WorkloadGVK.Kind)
 	assert.Equal("httpbin-v3", workloads[2].Name)
 	assert.Equal(false, workloads[2].AppLabel)
 	assert.Equal(false, workloads[2].VersionLabel)
-	assert.Equal("DaemonSet", workloads[2].Type)
+	assert.Equal("DaemonSet", workloads[2].WorkloadGVK.Kind)
 }
 
 func TestGetWorkloadListFromDepRCPod(t *testing.T) {
@@ -322,7 +322,7 @@ func TestGetWorkloadListFromDepRCPod(t *testing.T) {
 
 	require.Equal(1, len(workloads))
 	assert.Equal("details-v1", workloads[0].Name)
-	assert.Equal("Deployment", workloads[0].Type)
+	assert.Equal("Deployment", workloads[0].WorkloadGVK.Kind)
 	assert.Equal(true, workloads[0].AppLabel)
 	assert.Equal(true, workloads[0].VersionLabel)
 }
@@ -352,7 +352,7 @@ func TestGetWorkloadListFromPod(t *testing.T) {
 
 	require.Equal(1, len(workloads))
 	assert.Equal("orphan-pod", workloads[0].Name)
-	assert.Equal("Pod", workloads[0].Type)
+	assert.Equal("Pod", workloads[0].WorkloadGVK.Kind)
 	assert.Equal(true, workloads[0].AppLabel)
 	assert.Equal(true, workloads[0].VersionLabel)
 }
@@ -386,7 +386,7 @@ func TestGetWorkloadListFromPods(t *testing.T) {
 
 	require.Equal(1, len(workloads))
 	assert.Equal("custom-controller-RS-123", workloads[0].Name)
-	assert.Equal("ReplicaSet", workloads[0].Type)
+	assert.Equal("ReplicaSet", workloads[0].WorkloadGVK.Kind)
 	assert.Equal(true, workloads[0].AppLabel)
 	assert.Equal(true, workloads[0].VersionLabel)
 }
@@ -416,12 +416,12 @@ func TestGetWorkloadFromDeployment(t *testing.T) {
 	SetupBusinessLayer(t, k8s, *conf)
 	svc := setupWorkloadService(k8s, conf)
 
-	criteria := WorkloadCriteria{Cluster: conf.KubernetesConfig.ClusterName, Namespace: "Namespace", WorkloadName: "details-v1", WorkloadType: "", IncludeServices: false}
+	criteria := WorkloadCriteria{Cluster: conf.KubernetesConfig.ClusterName, Namespace: "Namespace", WorkloadName: "details-v1", WorkloadGVK: schema.GroupVersionKind{}, IncludeServices: false}
 	workload, err := svc.GetWorkload(context.TODO(), criteria)
 	require.NoError(err)
 
 	assert.Equal("details-v1", workload.Name)
-	assert.Equal("Deployment", workload.Type)
+	assert.Equal("Deployment", workload.WorkloadGVK.Kind)
 	assert.Equal(true, workload.AppLabel)
 	assert.Equal(true, workload.VersionLabel)
 }
@@ -454,12 +454,12 @@ func TestGetWorkloadWithInvalidWorkloadType(t *testing.T) {
 	SetupBusinessLayer(t, k8s, *conf)
 	svc := setupWorkloadService(k8s, conf)
 
-	criteria := WorkloadCriteria{Cluster: conf.KubernetesConfig.ClusterName, Namespace: "Namespace", WorkloadName: "details-v1", WorkloadType: "invalid", IncludeServices: false}
+	criteria := WorkloadCriteria{Cluster: conf.KubernetesConfig.ClusterName, Namespace: "Namespace", WorkloadName: "details-v1", WorkloadGVK: schema.GroupVersionKind{Kind: "invalid"}, IncludeServices: false}
 	workload, err := svc.GetWorkload(context.TODO(), criteria)
 	require.NoError(err)
 
 	assert.Equal("details-v1", workload.Name)
-	assert.Equal("Deployment", workload.Type)
+	assert.Equal("Deployment", workload.WorkloadGVK.Kind)
 	assert.Equal(true, workload.AppLabel)
 	assert.Equal(true, workload.VersionLabel)
 }
@@ -491,19 +491,19 @@ func TestGetWorkloadFromPods(t *testing.T) {
 	SetupBusinessLayer(t, k8s, *conf)
 	svc := setupWorkloadService(k8s, conf)
 
-	criteria := WorkloadCriteria{Cluster: conf.KubernetesConfig.ClusterName, Namespace: "Namespace", WorkloadName: "custom-controller", WorkloadType: "", IncludeServices: false}
+	criteria := WorkloadCriteria{Cluster: conf.KubernetesConfig.ClusterName, Namespace: "Namespace", WorkloadName: "custom-controller", WorkloadGVK: schema.GroupVersionKind{}, IncludeServices: false}
 	workload, err := svc.GetWorkload(context.TODO(), criteria)
 	require.Error(err)
 
 	// custom controller is not a workload type, only its replica set(s)
 	assert.Equal((*models.Workload)(nil), workload)
 
-	criteria = WorkloadCriteria{Cluster: conf.KubernetesConfig.ClusterName, Namespace: "Namespace", WorkloadName: "custom-controller-RS-123", WorkloadType: "", IncludeServices: false}
+	criteria = WorkloadCriteria{Cluster: conf.KubernetesConfig.ClusterName, Namespace: "Namespace", WorkloadName: "custom-controller-RS-123", WorkloadGVK: schema.GroupVersionKind{}, IncludeServices: false}
 	workload, err = svc.GetWorkload(context.TODO(), criteria)
 	require.NoError(err)
 
 	assert.Equal("custom-controller-RS-123", workload.Name)
-	assert.Equal("ReplicaSet", workload.Type)
+	assert.Equal("ReplicaSet", workload.WorkloadGVK.Kind)
 	assert.Equal(true, workload.AppLabel)
 	assert.Equal(true, workload.VersionLabel)
 	assert.Equal(0, len(workload.Runtimes))
@@ -803,11 +803,11 @@ func TestDuplicatedControllers(t *testing.T) {
 
 	workloads := workloadList.Workloads
 
-	criteria = WorkloadCriteria{Cluster: conf.KubernetesConfig.ClusterName, Namespace: "Namespace", WorkloadName: "duplicated-v1", WorkloadType: "", IncludeServices: false}
+	criteria = WorkloadCriteria{Cluster: conf.KubernetesConfig.ClusterName, Namespace: "Namespace", WorkloadName: "duplicated-v1", WorkloadGVK: schema.GroupVersionKind{}, IncludeServices: false}
 	workload, err := svc.GetWorkload(context.TODO(), criteria)
 
 	require.NoError(err)
-	assert.Equal(workloads[0].Type, workload.Type)
+	assert.Equal(workloads[0].WorkloadGVK.String(), workload.WorkloadGVK.String())
 }
 
 func TestGetWorkloadListFromGenericPodController(t *testing.T) {
@@ -851,7 +851,7 @@ func TestGetWorkloadListFromGenericPodController(t *testing.T) {
 	workloadList, _ := svc.GetWorkloadList(context.TODO(), criteria)
 	workloads := workloadList.Workloads
 
-	criteria = WorkloadCriteria{Cluster: conf.KubernetesConfig.ClusterName, Namespace: "Namespace", WorkloadName: owner.Name, WorkloadType: "", IncludeServices: false}
+	criteria = WorkloadCriteria{Cluster: conf.KubernetesConfig.ClusterName, Namespace: "Namespace", WorkloadName: owner.Name, WorkloadGVK: schema.GroupVersionKind{}, IncludeServices: false}
 	workload, err := svc.GetWorkload(context.TODO(), criteria)
 
 	require.NoError(err)
@@ -870,8 +870,8 @@ func TestGetWorkloadListKindsWithSameName(t *testing.T) {
 
 	rs := FakeRSSyncedWithPods()
 	pods := FakePodsSyncedWithDeployments()
-	pods[0].OwnerReferences[0].APIVersion = "shiny.new.apps/v1"
-	pods[0].OwnerReferences[0].Kind = "ReplicaSet"
+	pods[0].OwnerReferences[0].APIVersion = kubernetes.ReplicaSets.GroupVersion().String()
+	pods[0].OwnerReferences[0].Kind = kubernetes.ReplicaSets.Kind
 
 	// Setup mocks
 	kubeObjs := []runtime.Object{
@@ -995,7 +995,7 @@ func TestGetWorkloadListRSOwnedByCustom(t *testing.T) {
 	require.NoError(err)
 	workloads := workloadList.Workloads
 
-	criteria = WorkloadCriteria{Cluster: conf.KubernetesConfig.ClusterName, Namespace: "Namespace", WorkloadName: owner.Name, WorkloadType: "", IncludeServices: false}
+	criteria = WorkloadCriteria{Cluster: conf.KubernetesConfig.ClusterName, Namespace: "Namespace", WorkloadName: owner.Name, WorkloadGVK: schema.GroupVersionKind{}, IncludeServices: false}
 	workload, _ := svc.GetWorkload(context.TODO(), criteria)
 
 	require.Equal(len(workloads), 1)
@@ -1126,7 +1126,7 @@ func TestValidateWaypoint(t *testing.T) {
 	svc := setupWorkloadService(k8s, conf)
 
 	// Get waypoint proxy
-	criteria := WorkloadCriteria{Cluster: conf.KubernetesConfig.ClusterName, Namespace: "Namespace", WorkloadName: "waypoint", WorkloadType: "", IncludeServices: false}
+	criteria := WorkloadCriteria{Cluster: conf.KubernetesConfig.ClusterName, Namespace: "Namespace", WorkloadName: "waypoint", WorkloadGVK: schema.GroupVersionKind{}, IncludeServices: false}
 	workload, err := svc.GetWorkload(context.TODO(), criteria)
 
 	require.NoError(err)
@@ -1136,7 +1136,7 @@ func TestValidateWaypoint(t *testing.T) {
 	assert.True(workload.Pods[0].IsWaypoint())
 
 	// Get waypoint proxy
-	criteriaDetails := WorkloadCriteria{Cluster: conf.KubernetesConfig.ClusterName, Namespace: "Namespace", WorkloadName: "details", WorkloadType: "", IncludeServices: false}
+	criteriaDetails := WorkloadCriteria{Cluster: conf.KubernetesConfig.ClusterName, Namespace: "Namespace", WorkloadName: "details", WorkloadGVK: schema.GroupVersionKind{}, IncludeServices: false}
 	workloadDetails, errDetails := svc.GetWorkload(context.TODO(), criteriaDetails)
 
 	require.NoError(errDetails)
@@ -1147,7 +1147,7 @@ func TestValidateWaypoint(t *testing.T) {
 	assert.Equal("waypoint", workloadDetails.WaypointWorkloads[0].Name)
 
 	// productPage should not have a waypoint
-	criteriaProductPage := WorkloadCriteria{Cluster: conf.KubernetesConfig.ClusterName, Namespace: "Namespace", WorkloadName: "productpage", WorkloadType: "", IncludeServices: false}
+	criteriaProductPage := WorkloadCriteria{Cluster: conf.KubernetesConfig.ClusterName, Namespace: "Namespace", WorkloadName: "productpage", WorkloadGVK: schema.GroupVersionKind{}, IncludeServices: false}
 	workloadProductPage, errProductPage := svc.GetWorkload(context.TODO(), criteriaProductPage)
 
 	require.NoError(errProductPage)
@@ -1198,7 +1198,7 @@ func TestValidateWaypointNS(t *testing.T) {
 	svc := setupWorkloadService(k8s, conf)
 
 	// Get waypoint proxy
-	criteria := WorkloadCriteria{Cluster: conf.KubernetesConfig.ClusterName, Namespace: "Namespace", WorkloadName: "waypoint", WorkloadType: "", IncludeServices: false}
+	criteria := WorkloadCriteria{Cluster: conf.KubernetesConfig.ClusterName, Namespace: "Namespace", WorkloadName: "waypoint", WorkloadGVK: schema.GroupVersionKind{}, IncludeServices: false}
 	workload, err := svc.GetWorkload(context.TODO(), criteria)
 
 	require.NoError(err)
@@ -1208,7 +1208,7 @@ func TestValidateWaypointNS(t *testing.T) {
 	assert.True(workload.Pods[0].IsWaypoint())
 
 	// Get waypoint proxy
-	criteriaDetails := WorkloadCriteria{Cluster: conf.KubernetesConfig.ClusterName, Namespace: "Namespace", WorkloadName: "details", WorkloadType: "", IncludeServices: false}
+	criteriaDetails := WorkloadCriteria{Cluster: conf.KubernetesConfig.ClusterName, Namespace: "Namespace", WorkloadName: "details", WorkloadGVK: schema.GroupVersionKind{}, IncludeServices: false}
 	workloadDetails, errDetails := svc.GetWorkload(context.TODO(), criteriaDetails)
 
 	require.NoError(errDetails)
@@ -1219,7 +1219,7 @@ func TestValidateWaypointNS(t *testing.T) {
 	assert.Equal("waypoint", workloadDetails.WaypointWorkloads[0].Name)
 
 	// productPage should have also a waypoint
-	criteriaProductPage := WorkloadCriteria{Cluster: conf.KubernetesConfig.ClusterName, Namespace: "Namespace", WorkloadName: "productpage", WorkloadType: "", IncludeServices: false}
+	criteriaProductPage := WorkloadCriteria{Cluster: conf.KubernetesConfig.ClusterName, Namespace: "Namespace", WorkloadName: "productpage", WorkloadGVK: schema.GroupVersionKind{}, IncludeServices: false}
 	workloadProductPage, errProductPage := svc.GetWorkload(context.TODO(), criteriaProductPage)
 
 	require.NoError(errProductPage)
@@ -1263,7 +1263,7 @@ func TestValidateWaypointService(t *testing.T) {
 	svc := setupWorkloadService(k8s, conf)
 
 	// Get waypoint proxy
-	criteria := WorkloadCriteria{Cluster: conf.KubernetesConfig.ClusterName, Namespace: "Namespace", WorkloadName: "waypoint", WorkloadType: "", IncludeServices: false}
+	criteria := WorkloadCriteria{Cluster: conf.KubernetesConfig.ClusterName, Namespace: "Namespace", WorkloadName: "waypoint", WorkloadGVK: schema.GroupVersionKind{}, IncludeServices: false}
 	workload, err := svc.GetWorkload(context.TODO(), criteria)
 
 	require.NoError(err)
@@ -1273,7 +1273,7 @@ func TestValidateWaypointService(t *testing.T) {
 	assert.True(workload.Pods[0].IsWaypoint())
 
 	// Get waypoint proxy
-	criteriaDetails := WorkloadCriteria{Cluster: conf.KubernetesConfig.ClusterName, Namespace: "Namespace", WorkloadName: "details", WorkloadType: "", IncludeServices: false}
+	criteriaDetails := WorkloadCriteria{Cluster: conf.KubernetesConfig.ClusterName, Namespace: "Namespace", WorkloadName: "details", WorkloadGVK: schema.GroupVersionKind{}, IncludeServices: false}
 	workloadDetails, errDetails := svc.GetWorkload(context.TODO(), criteriaDetails)
 
 	require.NoError(errDetails)
@@ -1284,7 +1284,7 @@ func TestValidateWaypointService(t *testing.T) {
 	assert.Equal("waypoint", workloadDetails.WaypointWorkloads[0].Name)
 
 	// productPage should not have a waypoint
-	criteriaProductPage := WorkloadCriteria{Cluster: conf.KubernetesConfig.ClusterName, Namespace: "Namespace", WorkloadName: "productpage", WorkloadType: "", IncludeServices: false}
+	criteriaProductPage := WorkloadCriteria{Cluster: conf.KubernetesConfig.ClusterName, Namespace: "Namespace", WorkloadName: "productpage", WorkloadGVK: schema.GroupVersionKind{}, IncludeServices: false}
 	workloadProductPage, errProductPage := svc.GetWorkload(context.TODO(), criteriaProductPage)
 
 	require.NoError(errProductPage)
@@ -1365,3 +1365,36 @@ func TestGetAllGateways(t *testing.T) {
 	require.Len(workloads, 1)
 	require.True(workloads[0].IsGateway(), "Expected IsGateway to be True but it was false")
 }
+
+func TestGetWorkloadListWithCustomKindThatMatchesCoreKind(t *testing.T) {
+	assert := assert.New(t)
+	require := require.New(t)
+
+	conf := config.NewConfig()
+
+	kubeObjs := []runtime.Object{
+		&osproject_v1.Project{ObjectMeta: v1.ObjectMeta{Name: "Namespace"}},
+	}
+	for _, pod := range FakePodsFromCustomController() {
+		p := pod
+		// Setting here a custom type whose Kind matches a core Kube type.
+		p.OwnerReferences[0].APIVersion = "customAPI/v1"
+		p.OwnerReferences[0].Kind = "DaemonSet"
+		kubeObjs = append(kubeObjs, &p)
+	}
+
+	k8s := kubetest.NewFakeK8sClient(kubeObjs...)
+	k8s.OpenShift = true
+	SetupBusinessLayer(t, k8s, *conf)
+	svc := setupWorkloadService(k8s, conf)
+
+	criteria := WorkloadCriteria{Namespace: "Namespace", IncludeIstioResources: false, IncludeHealth: false}
+	workloadList, _ := svc.GetWorkloadList(context.TODO(), criteria)
+	workloads := workloadList.Workloads
+
+	assert.Equal("Namespace", workloadList.Namespace)
+
+	require.Equal(1, len(workloads))
+	assert.Equal("custom-controller-RS-123", workloads[0].Name)
+	assert.Equal("DaemonSet", workloads[0].WorkloadGVK.Kind)
+}
diff --git a/frontend/src/helpers/__tests__/LabelFilterHelper.test.ts b/frontend/src/helpers/__tests__/LabelFilterHelper.test.ts
index 06e5d5393..896b64772 100644
--- a/frontend/src/helpers/__tests__/LabelFilterHelper.test.ts
+++ b/frontend/src/helpers/__tests__/LabelFilterHelper.test.ts
@@ -6,6 +6,7 @@ import { InstanceType } from 'types/Common';
 import { ServiceListItem } from '../../types/ServiceList';
 import { setServerConfig } from '../../config/ServerConfig';
 import { serverRateConfig } from '../../types/ErrorRate/__testData__/ErrorRateConfig';
+import { dicTypeToGVK, gvkType } from '../../types/IstioConfigList';
 
 setServerConfig(serverRateConfig);
 const emptyAppHealth = new AppHealth(
@@ -80,7 +81,7 @@ const workloadList: WorkloadListItem[] = [
     namespace: 'bookinfo',
     health: emptyWorkHealth,
     name: 'details-v1',
-    type: 'Deployment',
+    gvk: dicTypeToGVK[gvkType.Deployment],
     istioSidecar: false,
     isAmbient: false,
     isGateway: false,
@@ -95,7 +96,7 @@ const workloadList: WorkloadListItem[] = [
     namespace: 'bookinfo',
     health: emptyWorkHealth,
     name: 'productpage-v1',
-    type: 'Deployment',
+    gvk: dicTypeToGVK[gvkType.Deployment],
     istioSidecar: false,
     isAmbient: false,
     isGateway: false,
@@ -110,7 +111,7 @@ const workloadList: WorkloadListItem[] = [
     namespace: 'bookinfo',
     health: emptyWorkHealth,
     name: 'ratings-v1',
-    type: 'Deployment',
+    gvk: dicTypeToGVK[gvkType.Deployment],
     istioSidecar: false,
     isAmbient: false,
     isGateway: false,
@@ -125,7 +126,7 @@ const workloadList: WorkloadListItem[] = [
     namespace: 'bookinfo',
     health: emptyWorkHealth,
     name: 'reviews-v1',
-    type: 'Deployment',
+    gvk: dicTypeToGVK[gvkType.Deployment],
     istioSidecar: false,
     isAmbient: false,
     isGateway: false,
@@ -140,7 +141,7 @@ const workloadList: WorkloadListItem[] = [
     namespace: 'bookinfo',
     health: emptyWorkHealth,
     name: 'reviews-v2',
-    type: 'Deployment',
+    gvk: dicTypeToGVK[gvkType.Deployment],
     istioSidecar: false,
     isAmbient: false,
     isGateway: false,
@@ -155,7 +156,7 @@ const workloadList: WorkloadListItem[] = [
     namespace: 'bookinfo',
     health: emptyWorkHealth,
     name: 'reviews-v3',
-    type: 'Deployment',
+    gvk: dicTypeToGVK[gvkType.Deployment],
     istioSidecar: false,
     isAmbient: false,
     isGateway: false,
@@ -285,7 +286,7 @@ describe('LabelFilter', () => {
         instanceType: InstanceType.Workload,
         health: emptyWorkHealth,
         name: 'reviews-v1',
-        type: 'Deployment',
+        gvk: dicTypeToGVK[gvkType.Deployment],
         istioSidecar: false,
         isAmbient: false,
         isGateway: false,
@@ -300,7 +301,7 @@ describe('LabelFilter', () => {
         instanceType: InstanceType.Workload,
         health: emptyWorkHealth,
         name: 'reviews-v2',
-        type: 'Deployment',
+        gvk: dicTypeToGVK[gvkType.Deployment],
         istioSidecar: false,
         isAmbient: false,
         isGateway: false,
@@ -315,7 +316,7 @@ describe('LabelFilter', () => {
         instanceType: InstanceType.Workload,
         health: emptyWorkHealth,
         name: 'reviews-v3',
-        type: 'Deployment',
+        gvk: dicTypeToGVK[gvkType.Deployment],
         istioSidecar: false,
         isAmbient: false,
         isGateway: false,
diff --git a/frontend/src/pages/IstioConfigList/__tests__/IstioConfigListComponent.test.ts b/frontend/src/pages/IstioConfigList/__tests__/IstioConfigListComponent.test.ts
index cd1ee30bc..c3a6ced80 100644
--- a/frontend/src/pages/IstioConfigList/__tests__/IstioConfigListComponent.test.ts
+++ b/frontend/src/pages/IstioConfigList/__tests__/IstioConfigListComponent.test.ts
@@ -1,6 +1,7 @@
 import {
-  dicIstioTypeToGVK,
+  dicTypeToGVK,
   filterByName,
+  gvkType,
   IstioConfigItem,
   IstioConfigList,
   toIstioItems
@@ -15,40 +16,42 @@ const mockIstioConfigList = (names: string[]): IstioConfigList => {
     permissions: {},
     resources: {}
   };
-  Object.keys(dicIstioTypeToGVK).forEach(index => {
+  Object.values(dicTypeToGVK).forEach(index => {
     const key = getGVKTypeString(index);
     testData.resources[key] = [];
   });
   names.forEach(name => {
-    testData.resources[getGVKTypeString('AuthorizationPolicy')].push({
+    testData.resources[getGVKTypeString(gvkType.AuthorizationPolicy)].push({
       metadata: { name: `${name}0` },
       spec: {},
-      kind: dicIstioTypeToGVK['AuthorizationPolicy'].Kind,
-      apiVersion: `${dicIstioTypeToGVK['AuthorizationPolicy'].Group}/${dicIstioTypeToGVK['AuthorizationPolicy'].Version}`
+      kind: dicTypeToGVK[gvkType.AuthorizationPolicy].Kind,
+      apiVersion: `${dicTypeToGVK[gvkType.AuthorizationPolicy].Group}/${
+        dicTypeToGVK[gvkType.AuthorizationPolicy].Version
+      }`
     });
-    testData.resources[getGVKTypeString('DestinationRule')].push({
+    testData.resources[getGVKTypeString(gvkType.DestinationRule)].push({
       metadata: { name: `${name}1` },
       spec: {},
-      kind: dicIstioTypeToGVK['DestinationRule'].Kind,
-      apiVersion: `${dicIstioTypeToGVK['DestinationRule'].Group}/${dicIstioTypeToGVK['DestinationRule'].Version}`
+      kind: dicTypeToGVK[gvkType.DestinationRule].Kind,
+      apiVersion: `${dicTypeToGVK[gvkType.DestinationRule].Group}/${dicTypeToGVK[gvkType.DestinationRule].Version}`
     });
-    testData.resources[getGVKTypeString('Gateway')].push({
+    testData.resources[getGVKTypeString(gvkType.Gateway)].push({
       metadata: { name: `${name}2` },
       spec: {},
-      kind: dicIstioTypeToGVK['Gateway'].Kind,
-      apiVersion: `${dicIstioTypeToGVK['Gateway'].Group}/${dicIstioTypeToGVK['Gateway'].Version}`
+      kind: dicTypeToGVK[gvkType.Gateway].Kind,
+      apiVersion: `${dicTypeToGVK[gvkType.Gateway].Group}/${dicTypeToGVK[gvkType.Gateway].Version}`
     });
-    testData.resources[getGVKTypeString('ServiceEntry')].push({
+    testData.resources[getGVKTypeString(gvkType.ServiceEntry)].push({
       metadata: { name: `${name}3` },
       spec: {},
-      kind: dicIstioTypeToGVK['ServiceEntry'].Kind,
-      apiVersion: `${dicIstioTypeToGVK['ServiceEntry'].Group}/${dicIstioTypeToGVK['ServiceEntry'].Version}`
+      kind: dicTypeToGVK[gvkType.ServiceEntry].Kind,
+      apiVersion: `${dicTypeToGVK[gvkType.ServiceEntry].Group}/${dicTypeToGVK[gvkType.ServiceEntry].Version}`
     });
-    testData.resources[getGVKTypeString('VirtualService')].push({
+    testData.resources[getGVKTypeString(gvkType.VirtualService)].push({
       metadata: { name: `${name}4` },
       spec: {},
-      kind: dicIstioTypeToGVK['VirtualService'].Kind,
-      apiVersion: `${dicIstioTypeToGVK['VirtualService'].Group}/${dicIstioTypeToGVK['VirtualService'].Version}`
+      kind: dicTypeToGVK[gvkType.VirtualService].Kind,
+      apiVersion: `${dicTypeToGVK[gvkType.VirtualService].Group}/${dicTypeToGVK[gvkType.VirtualService].Version}`
     });
   });
   return testData;
@@ -60,30 +63,30 @@ describe('IstioConfigList#filterByName', () => {
   it('should filter IstioConfigList by name', () => {
     let filtered = filterByName(unfiltered, ['white', 'red']);
     expect(filtered).toBeDefined();
-    expect(filtered.resources[getGVKTypeString('Gateway')].length).toBe(2);
-    expect(filtered.resources[getGVKTypeString('VirtualService')].length).toBe(2);
-    expect(filtered.resources[getGVKTypeString('DestinationRule')].length).toBe(2);
-    expect(filtered.resources[getGVKTypeString('ServiceEntry')].length).toBe(2);
+    expect(filtered.resources[getGVKTypeString(gvkType.Gateway)].length).toBe(2);
+    expect(filtered.resources[getGVKTypeString(gvkType.VirtualService)].length).toBe(2);
+    expect(filtered.resources[getGVKTypeString(gvkType.DestinationRule)].length).toBe(2);
+    expect(filtered.resources[getGVKTypeString(gvkType.ServiceEntry)].length).toBe(2);
 
-    expect(filtered.resources[getGVKTypeString('AuthorizationPolicy')][0].metadata.name).toBe('white0');
-    expect(filtered.resources[getGVKTypeString('DestinationRule')][0].metadata.name).toBe('white1');
-    expect(filtered.resources[getGVKTypeString('ServiceEntry')][0].metadata.name).toBe('white3');
-    expect(filtered.resources[getGVKTypeString('VirtualService')][0].metadata.name).toBe('white4');
+    expect(filtered.resources[getGVKTypeString(gvkType.AuthorizationPolicy)][0].metadata.name).toBe('white0');
+    expect(filtered.resources[getGVKTypeString(gvkType.DestinationRule)][0].metadata.name).toBe('white1');
+    expect(filtered.resources[getGVKTypeString(gvkType.ServiceEntry)][0].metadata.name).toBe('white3');
+    expect(filtered.resources[getGVKTypeString(gvkType.VirtualService)][0].metadata.name).toBe('white4');
 
     filtered = filterByName(unfiltered, ['bad']);
     expect(filtered).toBeDefined();
-    expect(filtered.resources[getGVKTypeString('Gateway')].length).toBe(0);
-    expect(filtered.resources[getGVKTypeString('VirtualService')].length).toBe(0);
-    expect(filtered.resources[getGVKTypeString('DestinationRule')].length).toBe(0);
-    expect(filtered.resources[getGVKTypeString('ServiceEntry')].length).toBe(0);
-    expect(filtered.resources[getGVKTypeString('WasmPlugin')].length).toBe(0);
-    expect(filtered.resources[getGVKTypeString('Telemetry')].length).toBe(0);
-    expect(filtered.resources[getGVKTypeString('K8sGateway')].length).toBe(0);
-    expect(filtered.resources[getGVKTypeString('K8sGRPCRoute')].length).toBe(0);
-    expect(filtered.resources[getGVKTypeString('K8sHTTPRoute')].length).toBe(0);
-    expect(filtered.resources[getGVKTypeString('K8sReferenceGrant')].length).toBe(0);
-    expect(filtered.resources[getGVKTypeString('K8sTCPRoute')].length).toBe(0);
-    expect(filtered.resources[getGVKTypeString('K8sTLSRoute')].length).toBe(0);
+    expect(filtered.resources[getGVKTypeString(gvkType.Gateway)].length).toBe(0);
+    expect(filtered.resources[getGVKTypeString(gvkType.VirtualService)].length).toBe(0);
+    expect(filtered.resources[getGVKTypeString(gvkType.DestinationRule)].length).toBe(0);
+    expect(filtered.resources[getGVKTypeString(gvkType.ServiceEntry)].length).toBe(0);
+    expect(filtered.resources[getGVKTypeString(gvkType.WasmPlugin)].length).toBe(0);
+    expect(filtered.resources[getGVKTypeString(gvkType.Telemetry)].length).toBe(0);
+    expect(filtered.resources[getGVKTypeString(gvkType.K8sGateway)].length).toBe(0);
+    expect(filtered.resources[getGVKTypeString(gvkType.K8sGRPCRoute)].length).toBe(0);
+    expect(filtered.resources[getGVKTypeString(gvkType.K8sHTTPRoute)].length).toBe(0);
+    expect(filtered.resources[getGVKTypeString(gvkType.K8sReferenceGrant)].length).toBe(0);
+    expect(filtered.resources[getGVKTypeString(gvkType.K8sTCPRoute)].length).toBe(0);
+    expect(filtered.resources[getGVKTypeString(gvkType.K8sTLSRoute)].length).toBe(0);
   });
 });
 
@@ -94,11 +97,11 @@ describe('IstioConfigListContainer#toIstioItems', () => {
     expect(istioItems).toBeDefined();
     expect(istioItems.length).toBe(15);
     expect(istioItems[0].resource).toBeDefined();
-    expect(istioItems[0].resource.kind).toBe(dicIstioTypeToGVK['AuthorizationPolicy'].Kind);
+    expect(istioItems[0].resource.kind).toBe(dicTypeToGVK[gvkType.AuthorizationPolicy].Kind);
     expect(istioItems[3].resource).toBeDefined();
-    expect(istioItems[3].resource.kind).toBe(dicIstioTypeToGVK['DestinationRule'].Kind);
+    expect(istioItems[3].resource.kind).toBe(dicTypeToGVK[gvkType.DestinationRule].Kind);
     expect(istioItems[6].resource).toBeDefined();
-    expect(istioItems[6].resource.kind).toBe(dicIstioTypeToGVK['Gateway'].Kind);
+    expect(istioItems[6].resource.kind).toBe(dicTypeToGVK[gvkType.Gateway].Kind);
   });
 });
 
@@ -114,17 +117,17 @@ describe('IstioConfigComponent#sortIstioItems', () => {
 
     const first = sorted[0];
     expect(first.resource).toBeDefined();
-    expect(first.resource.kind).toBe(dicIstioTypeToGVK['AuthorizationPolicy'].Kind);
+    expect(first.resource.kind).toBe(dicTypeToGVK[gvkType.AuthorizationPolicy].Kind);
     expect(first.resource.metadata.name).toBe('blue0');
 
     const second = sorted[1];
     expect(second.resource).toBeDefined();
-    expect(second.resource.kind).toBe(dicIstioTypeToGVK['DestinationRule'].Kind);
+    expect(second.resource.kind).toBe(dicTypeToGVK[gvkType.DestinationRule].Kind);
     expect(second.resource.metadata.name).toBe('blue1');
 
     const last = sorted[14];
     expect(last.resource).toBeDefined();
-    expect(last.resource.kind).toBe(dicIstioTypeToGVK['VirtualService'].Kind);
+    expect(last.resource.kind).toBe(dicTypeToGVK[gvkType.VirtualService].Kind);
     expect(last.resource.metadata.name).toBe('white4');
   });
 
@@ -140,12 +143,12 @@ describe('IstioConfigComponent#sortIstioItems', () => {
 
     const first = sorted[0];
     expect(first.resource).toBeDefined();
-    expect(first.resource.kind).toBe(dicIstioTypeToGVK['VirtualService'].Kind);
+    expect(first.resource.kind).toBe(dicTypeToGVK[gvkType.VirtualService].Kind);
     expect(first.resource.metadata.name).toBe('white4');
 
     const last = sorted[14];
     expect(last.resource).toBeDefined();
-    expect(last.resource.kind).toBe(dicIstioTypeToGVK['AuthorizationPolicy'].Kind);
+    expect(last.resource.kind).toBe(dicTypeToGVK[gvkType.AuthorizationPolicy].Kind);
     expect(last.resource.metadata.name).toBe('blue0');
   });
 
@@ -160,17 +163,17 @@ describe('IstioConfigComponent#sortIstioItems', () => {
 
     const first = sorted[0];
     expect(first.resource).toBeDefined();
-    expect(first.resource.kind).toBe(dicIstioTypeToGVK['AuthorizationPolicy'].Kind);
+    expect(first.resource.kind).toBe(dicTypeToGVK[gvkType.AuthorizationPolicy].Kind);
     expect(first.resource.metadata.name).toBe('blue0');
 
     const second = sorted[3];
     expect(second.resource).toBeDefined();
-    expect(second.resource.kind).toBe(dicIstioTypeToGVK['DestinationRule'].Kind);
+    expect(second.resource.kind).toBe(dicTypeToGVK[gvkType.DestinationRule].Kind);
     expect(second.resource.metadata.name).toBe('blue1');
 
     const last = sorted[14];
     expect(last.resource).toBeDefined();
-    expect(last.resource.kind).toBe(dicIstioTypeToGVK['VirtualService'].Kind);
+    expect(last.resource.kind).toBe(dicTypeToGVK[gvkType.VirtualService].Kind);
     expect(last.resource.metadata.name).toBe('white4');
   });
 
@@ -185,7 +188,7 @@ describe('IstioConfigComponent#sortIstioItems', () => {
 
     const first = sorted[0];
     expect(first.resource).toBeDefined();
-    expect(first.resource.kind).toBe(dicIstioTypeToGVK['VirtualService'].Kind);
+    expect(first.resource.kind).toBe(dicTypeToGVK[gvkType.VirtualService].Kind);
     expect(first.resource.metadata.name).toBe('white4');
   });
 });
diff --git a/frontend/src/types/__tests__/AceValidations.test.ts b/frontend/src/types/__tests__/AceValidations.test.ts
index d4a70cef2..cb2bc515e 100644
--- a/frontend/src/types/__tests__/AceValidations.test.ts
+++ b/frontend/src/types/__tests__/AceValidations.test.ts
@@ -1,12 +1,12 @@
 import { ObjectValidation, ValidationTypes } from '../IstioObjects';
 import { parseKialiValidations } from '../AceValidations';
-import { dicIstioTypeToGVK } from '../IstioConfigList';
+import { dicTypeToGVK, gvkType } from '../IstioConfigList';
 
 const fs = require('fs');
 
 const destinationRuleValidations: ObjectValidation = {
   name: 'details',
-  objectGVK: dicIstioTypeToGVK['DestinationRule'],
+  objectGVK: dicTypeToGVK[gvkType.DestinationRule],
   valid: false,
   checks: [
     {
@@ -19,7 +19,7 @@ const destinationRuleValidations: ObjectValidation = {
 
 const vsInvalidHosts: ObjectValidation = {
   name: 'productpage',
-  objectGVK: dicIstioTypeToGVK['VirtualService'],
+  objectGVK: dicTypeToGVK[gvkType.VirtualService],
   valid: false,
   checks: [
     {
@@ -32,7 +32,7 @@ const vsInvalidHosts: ObjectValidation = {
 
 const vsInvalidHttpFirstRoute: ObjectValidation = {
   name: 'productpage',
-  objectGVK: dicIstioTypeToGVK['VirtualService'],
+  objectGVK: dicTypeToGVK[gvkType.VirtualService],
   valid: false,
   checks: [
     {
@@ -45,7 +45,7 @@ const vsInvalidHttpFirstRoute: ObjectValidation = {
 
 const vsInvalidHttpSecondRoute: ObjectValidation = {
   name: 'productpage',
-  objectGVK: dicIstioTypeToGVK['VirtualService'],
+  objectGVK: dicTypeToGVK[gvkType.VirtualService],
   valid: false,
   checks: [
     {
@@ -58,7 +58,7 @@ const vsInvalidHttpSecondRoute: ObjectValidation = {
 
 const vsInvalidHttpThirdRoute: ObjectValidation = {
   name: 'productpage',
-  objectGVK: dicIstioTypeToGVK['VirtualService'],
+  objectGVK: dicTypeToGVK[gvkType.VirtualService],
   valid: false,
   checks: [
     {
@@ -71,7 +71,7 @@ const vsInvalidHttpThirdRoute: ObjectValidation = {
 
 const vsInvalidHttpSecondSecondDestinationField: ObjectValidation = {
   name: 'productpage',
-  objectGVK: dicIstioTypeToGVK['VirtualService'],
+  objectGVK: dicTypeToGVK[gvkType.VirtualService],
   valid: false,
   checks: [
     {
@@ -84,7 +84,7 @@ const vsInvalidHttpSecondSecondDestinationField: ObjectValidation = {
 
 const vsInvalidHttpThirdFirstDestinationField: ObjectValidation = {
   name: 'productpage',
-  objectGVK: dicIstioTypeToGVK['VirtualService'],
+  objectGVK: dicTypeToGVK[gvkType.VirtualService],
   valid: false,
   checks: [
     {
@@ -97,7 +97,7 @@ const vsInvalidHttpThirdFirstDestinationField: ObjectValidation = {
 
 const vsInvalidHttpThirdFirstSubsetNotFound: ObjectValidation = {
   name: 'productpage',
-  objectGVK: dicIstioTypeToGVK['VirtualService'],
+  objectGVK: dicTypeToGVK[gvkType.VirtualService],
   valid: false,
   checks: [
     {
@@ -110,7 +110,7 @@ const vsInvalidHttpThirdFirstSubsetNotFound: ObjectValidation = {
 
 const vsInvalidHttpFirstSecondSubsetNotFound: ObjectValidation = {
   name: 'productpage',
-  objectGVK: dicIstioTypeToGVK['VirtualService'],
+  objectGVK: dicTypeToGVK[gvkType.VirtualService],
   valid: false,
   checks: [
     {
@@ -123,7 +123,7 @@ const vsInvalidHttpFirstSecondSubsetNotFound: ObjectValidation = {
 
 const vsInvalidHttpFourthFirstWeigth: ObjectValidation = {
   name: 'productpage',
-  objectGVK: dicIstioTypeToGVK['VirtualService'],
+  objectGVK: dicTypeToGVK[gvkType.VirtualService],
   valid: false,
   checks: [
     {
@@ -136,7 +136,7 @@ const vsInvalidHttpFourthFirstWeigth: ObjectValidation = {
 
 const vsInvalidHttpFifthSecondWeigth: ObjectValidation = {
   name: 'productpage',
-  objectGVK: dicIstioTypeToGVK['VirtualService'],
+  objectGVK: dicTypeToGVK[gvkType.VirtualService],
   valid: false,
   checks: [
     {
diff --git a/frontend/src/utils/__tests__/IstioConfigUtils.test.ts b/frontend/src/utils/__tests__/IstioConfigUtils.test.ts
index b68bc5b77..45625145a 100644
--- a/frontend/src/utils/__tests__/IstioConfigUtils.test.ts
+++ b/frontend/src/utils/__tests__/IstioConfigUtils.test.ts
@@ -8,7 +8,7 @@ import {
   mergeJsonPatch,
   stringToGVK
 } from '../IstioConfigUtils';
-import { dicIstioTypeToGVK } from '../../types/IstioConfigList';
+import { dicTypeToGVK, gvkType } from '../../types/IstioConfigList';
 
 describe('Validate JSON Patchs', () => {
   const gateway: object = {
@@ -119,7 +119,7 @@ describe('Validate returned GoupVersionKind for IstioObject', () => {
 
   it('Invalid apiVersion, valid Kind', () => {
     const result = getIstioObjectGVK('invalidApiVersion', 'AuthorizationPolicy');
-    expect(result).toEqual(dicIstioTypeToGVK['AuthorizationPolicy']);
+    expect(result).toEqual(dicTypeToGVK[gvkType.AuthorizationPolicy]);
   });
 
   it('Empty apiVersion, valid kind', () => {
@@ -139,6 +139,21 @@ describe('Validate converting GroupVersionKind To String', () => {
     expect(result).toBe('networking.istio.io/v1, Kind=VirtualService');
   });
 
+  it('Correct Workload GroupVersionKind properties', () => {
+    const result = getGVKTypeString({ Group: 'apps', Version: 'v1', Kind: 'Deployment' });
+    expect(result).toBe('apps/v1, Kind=Deployment');
+  });
+
+  it('Correct Workload Kind properties', () => {
+    const result = getGVKTypeString(gvkType.Deployment);
+    expect(result).toBe('apps/v1, Kind=Deployment');
+  });
+
+  it('Correct Gateway Kind properties', () => {
+    const result = getGVKTypeString(gvkType.Gateway);
+    expect(result).toBe('networking.istio.io/v1, Kind=Gateway');
+  });
+
   it('Validate empty string when Group, Version, and Kind are all empty', () => {
     const result = getGVKTypeString({ Group: '', Version: '', Kind: '' });
     expect(result).toBe('');
diff --git a/kubernetes/filters_test.go b/kubernetes/filters_test.go
index 5dc3c843a..cb51260c8 100644
--- a/kubernetes/filters_test.go
+++ b/kubernetes/filters_test.go
@@ -11,6 +11,7 @@ import (
 	meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/labels"
 	"k8s.io/apimachinery/pkg/runtime"
+	"k8s.io/apimachinery/pkg/runtime/schema"
 	"k8s.io/apimachinery/pkg/types"
 	k8s_networking_v1 "sigs.k8s.io/gateway-api/apis/v1"
 	k8s_networking_v1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1"
@@ -146,19 +147,19 @@ func TestFilterPodsByController(t *testing.T) {
 			UID:  types.UID("e07b722f-c922-4046-8d98-7aa8487d41c1"),
 		},
 		TypeMeta: meta_v1.TypeMeta{
-			Kind:       "ReplicaSet",
-			APIVersion: apps_v1.SchemeGroupVersion.String(),
+			Kind:       ReplicaSets.Kind,
+			APIVersion: ReplicaSets.GroupVersion().String(),
 		},
 	}
 	cases := map[string]struct {
 		controllerName string
-		controllerType string
+		controllerGVK  schema.GroupVersionKind
 		pods           []core_v1.Pod
 		expectedLen    int
 	}{
 		"Filters by kind and full name": {
 			controllerName: rs.Name,
-			controllerType: "ReplicaSet",
+			controllerGVK:  ReplicaSets,
 			pods: []core_v1.Pod{
 				{
 					ObjectMeta: meta_v1.ObjectMeta{
@@ -176,7 +177,7 @@ func TestFilterPodsByController(t *testing.T) {
 		},
 		"Includes APIVersion": {
 			controllerName: rs.Name,
-			controllerType: "ReplicaSet",
+			controllerGVK:  ReplicaSets,
 			pods: []core_v1.Pod{
 				{
 					ObjectMeta: meta_v1.ObjectMeta{
@@ -189,8 +190,7 @@ func TestFilterPodsByController(t *testing.T) {
 					},
 				},
 			},
-			// TODO: This should be 0
-			expectedLen: 1,
+			expectedLen: 0,
 		},
 	}
 
@@ -198,7 +198,7 @@ func TestFilterPodsByController(t *testing.T) {
 		t.Run(name, func(t *testing.T) {
 			assert := assert.New(t)
 
-			pods := FilterPodsByController(tc.controllerName, tc.controllerType, tc.pods)
+			pods := FilterPodsByController(tc.controllerName, tc.controllerGVK, tc.pods)
 			assert.Equal(tc.expectedLen, len(pods))
 		})
 	}
diff --git a/kubernetes/kubetest/mock_kubernetes.go b/kubernetes/kubetest/mock_kubernetes.go
index dcb6204e3..c82444ef5 100644
--- a/kubernetes/kubetest/mock_kubernetes.go
+++ b/kubernetes/kubetest/mock_kubernetes.go
@@ -9,6 +9,7 @@ import (
 	batch_v1 "k8s.io/api/batch/v1"
 	core_v1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/runtime/schema"
 	"k8s.io/client-go/kubernetes"
 )
 
@@ -156,8 +157,8 @@ func (o *K8SClientMock) UpdateNamespace(namespace string, jsonPatch string) (*co
 	return args.Get(0).(*core_v1.Namespace), args.Error(1)
 }
 
-func (o *K8SClientMock) UpdateWorkload(namespace string, name string, workloadType string, jsonPatch string, patchType string) error {
-	args := o.Called(namespace, name, workloadType, jsonPatch, patchType)
+func (o *K8SClientMock) UpdateWorkload(namespace string, name string, workloadGVK schema.GroupVersionKind, jsonPatch string, patchType string) error {
+	args := o.Called(namespace, name, workloadGVK, jsonPatch, patchType)
 	return args.Error(1)
 }
 
diff --git a/models/workload_test.go b/models/workload_test.go
index 882419c20..0b070b6ee 100644
--- a/models/workload_test.go
+++ b/models/workload_test.go
@@ -10,6 +10,7 @@ import (
 	apps_v1 "k8s.io/api/apps/v1"
 	core_v1 "k8s.io/api/core/v1"
 	meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/runtime/schema"
 
 	"github.com/kiali/kiali/config"
 )
@@ -41,7 +42,7 @@ func TestParseDeploymentToWorkload(t *testing.T) {
 	assert.Equal("bar", w.Labels["foo"])
 	assert.Equal("v1", w.Labels["version"])
 	assert.Equal("2709198702082918", w.ResourceVersion)
-	assert.Equal("Deployment", w.Type)
+	assert.Equal("Deployment", w.WorkloadGVK.Kind)
 	assert.Equal(int32(1), w.DesiredReplicas)
 	assert.Equal(int32(1), w.CurrentReplicas)
 	assert.Equal(int32(1), w.AvailableReplicas)
@@ -75,7 +76,7 @@ func TestParseReplicaSetToWorkload(t *testing.T) {
 	assert.Equal("bar", w.Labels["foo"])
 	assert.Equal("v1", w.Labels["version"])
 	assert.Equal("2709198702082918", w.ResourceVersion)
-	assert.Equal("ReplicaSet", w.Type)
+	assert.Equal("ReplicaSet", w.WorkloadGVK.Kind)
 	assert.Equal(int32(1), w.DesiredReplicas)
 	assert.Equal(int32(1), w.CurrentReplicas)
 	assert.Equal(int32(1), w.AvailableReplicas)
@@ -102,7 +103,7 @@ func TestParseReplicationControllerToWorkload(t *testing.T) {
 	assert.Equal("bar", w.Labels["foo"])
 	assert.Equal("v1", w.Labels["version"])
 	assert.Equal("2709198702082918", w.ResourceVersion)
-	assert.Equal("ReplicationController", w.Type)
+	assert.Equal("ReplicationController", w.WorkloadGVK.Kind)
 	assert.Equal(int32(1), w.DesiredReplicas)
 	assert.Equal(int32(1), w.CurrentReplicas)
 	assert.Equal(int32(1), w.AvailableReplicas)
@@ -155,7 +156,7 @@ func TestParsePodToWorkload(t *testing.T) {
 	assert.Equal("bar", w.Labels["foo"])
 	assert.Equal("v1", w.Labels["version"])
 	assert.Equal("2709198702082918", w.ResourceVersion)
-	assert.Equal("Pod", w.Type)
+	assert.Equal("Pod", w.WorkloadGVK.Kind)
 	assert.Equal(int32(1), w.DesiredReplicas)
 	assert.Equal(int32(1), w.CurrentReplicas)
 	assert.Equal(int32(1), w.AvailableReplicas)
@@ -169,13 +170,13 @@ func TestParsePodsToWorkload(t *testing.T) {
 	config.Set(config.NewConfig())
 
 	w := Workload{}
-	w.ParsePods("workload-from-controller", "Controller", []core_v1.Pod{*fakePod()})
+	w.ParsePods("workload-from-controller", schema.GroupVersionKind{Kind: "Controller"}, []core_v1.Pod{*fakePod()})
 
 	assert.Equal("workload-from-controller", w.Name)
 	assert.Equal("bar", w.Labels["foo"])
 	assert.Equal("v1", w.Labels["version"])
 	assert.Equal("2709198702082918", w.ResourceVersion)
-	assert.Equal("Controller", w.Type)
+	assert.Equal("Controller", w.WorkloadGVK.Kind)
 	assert.Equal(int32(1), w.DesiredReplicas)
 	assert.Equal(int32(1), w.CurrentReplicas)
 	assert.Equal(int32(1), w.AvailableReplicas)
diff --git a/tests/integration/tests/no_istiod_test.go b/tests/integration/tests/no_istiod_test.go
index 3b41554f8..980c8bd8b 100644
--- a/tests/integration/tests/no_istiod_test.go
+++ b/tests/integration/tests/no_istiod_test.go
@@ -78,7 +78,7 @@ func noProxyStatus(t *testing.T) {
 	require.NoError(err)
 	require.NotNil(wl)
 	require.Equal(name, wl.Name)
-	require.Equal("Deployment", wl.Type)
+	require.Equal("Deployment", wl.WorkloadGVK.Kind)
 	require.NotNil(wl.Pods)
 	for _, pod := range wl.Pods {
 		require.NotEmpty(pod.Status)
diff --git a/tests/integration/tests/workloads_test.go b/tests/integration/tests/workloads_test.go
index aae823d92..f90cb3091 100644
--- a/tests/integration/tests/workloads_test.go
+++ b/tests/integration/tests/workloads_test.go
@@ -42,7 +42,7 @@ func TestWorkloadDetails(t *testing.T) {
 	require.NoError(err)
 	require.NotNil(wl)
 	require.Equal(name, wl.Name)
-	require.Equal("Deployment", wl.Type)
+	require.Equal("Deployment", wl.WorkloadGVK.Kind)
 	require.NotNil(wl.Pods)
 	for _, pod := range wl.Pods {
 		require.NotEmpty(pod.Status)
@@ -73,7 +73,7 @@ func TestWorkloadIstioIngressEmptyProxyStatus(t *testing.T) {
 	require.NoError(err)
 	require.NotNil(wl)
 	require.Equal(name, wl.Name)
-	require.Equal("Deployment", wl.Type)
+	require.Equal("Deployment", wl.WorkloadGVK.Kind)
 	require.NotNil(wl.Pods)
 	for _, pod := range wl.Pods {
 		require.NotEmpty(pod.Status)
@@ -109,7 +109,7 @@ func TestDiscoverWorkload(t *testing.T) {
 		foundWorkloads := 0
 		for _, wl := range wlList.Workloads {
 			for k, v := range extraWorkloads {
-				if k == wl.Name && v == wl.Type {
+				if k == wl.Name && v == wl.WorkloadGVK.Kind {
 					foundWorkloads++
 				}
 			}