Differences in Data Assets, Data Tables and Structures (Overall Hierarchies in systems)

My setup uses the C++ implementation so I can use the Get Owned Gameplay Tags Interface.

In your Build.cs file you have to add the dependency module GameplayTags

header

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "GameplayTagContainer.h"
#include "GameplayTagAssetInterface.h"
#include "BaseGamePlayTags.generated.h"


UCLASS()
class SURROGATE_V52_API ABaseGamePlayTags : public AActor, public IGameplayTagAssetInterface
{
	GENERATED_BODY()
	
public:	
	// Sets default values for this actor's properties
	ABaseGamePlayTags();

	// Gameplay Tag Container variable, Exposed to BP
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GameplayTags")
		FGameplayTagContainer ConfigTags;

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;

public:	
	// Called every frame
	virtual void Tick(float DeltaTime) override;

	// Get GameplayTags
	virtual void GetOwnedGameplayTags(FGameplayTagContainer& TagContainer) const override { TagContainer = ConfigTags; return; }

};

CPP

// Fill out your copyright notice in the Description page of Project Settings.


#include "BaseGamePlayTags.h"

// Sets default values
ABaseGamePlayTags::ABaseGamePlayTags()
{
 	// Set this actor to call Tick() every frame.
 	// You can turn this off to improve performance if you do not need it.

	PrimaryActorTick.bCanEverTick = true;

}

// Called when the game starts or when spawned
void ABaseGamePlayTags::BeginPlay()
{
	Super::BeginPlay();
	
}

// Called every frame
void ABaseGamePlayTags::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

}

I then create a base class in BP using the C++ class as parent. All Items derive from that class.

Dynamically setting is a matter of call Set Config Tags